Your browser lacks required capabilities. Please upgrade it or switch to another to continue.
Loading…
{
"name": "Vesper",
"ifid": "7032a282-b49c-5de1-9ef0-8553b88d1f63",
"format": "SugarCube",
"format-version": "2.30.0",
"start": "Start"
}<<set $player = {
"name": "Wren",
"portrait": "wren.jpg",
"current_location": "",
"core_traits": {
"energy": 100,
"money": 50,
"fighting": 0,
"stealth": 0,
"yard_depth": 0,
"weapon_repair": 0,
"coin": 0,
"equipped_weapon": 1,
"drain_charge": 1,
"arousal_charge": 0,
"corruption": 0,
"arousal": 0,
"hygiene": 100,
"sex_stage": 0,
"loop_npc_pleasure": 0,
"sex_finisher_type": 0,
"anal_active": 0,
"sex_entry_origin": 0,
"drains_done": 0,
"names_known": 0,
"core_strain": 0,
"cell_door": 0,
"core_sealed": 0,
"kess_debt": 0,
"repair_armed": 0,
"repair_session": 0,
"calloway_drains_done": 0,
"colm_drains_done": 0,
"case_progress": 0,
"vault_cleared": 0,
"emitter_broken": 0,
"feed_line_days": 0,
"part_held": 0,
"part_installed": 0,
"mercer_attempts": 0,
"part_spec": 0,
"spec_pending": 0,
"case_held": 0,
"mercer_drains_done": 0,
"mercer_leash_state": 0,
"controller_seated": 0,
"controller_through": 0,
"controller_state": 0,
"bastien_drains_done": 0,
"wall_refusals": 0,
"bar_rung": 0,
"taser_held": 0,
"taser_through": 0,
"ruin_depth": 0,
"pieces_seated": 0,
"grier_nights": 0,
"grier_drains_done": 0,
"sabin_drains_done": 0,
"sabin_suspects": 0,
"bottle_held": 0
},
"wardrobe": {
"company_grays": {
"id": "company_grays",
"name": "Company grays",
"slot": "dress",
"image": "./videos/clothing/company_grays.jpg"
},
"plain_bra": {
"id": "plain_bra",
"name": "Plain bra",
"slot": "bra",
"image": "./videos/clothing/plain_bra.jpg"
},
"plain_briefs": {
"id": "plain_briefs",
"name": "Plain briefs",
"slot": "underwear",
"image": "./videos/clothing/plain_briefs.jpg"
},
"flat_shoes": {
"id": "flat_shoes",
"name": "Flats",
"slot": "shoes",
"image": "./videos/clothing/flat_shoes.jpg"
}
},
"equipped": {
"bra": "plain_bra",
"underwear": "plain_briefs",
"top": null,
"bottom": null,
"dress": "company_grays",
"legwear": null,
"shoes": "flat_shoes"
}
}>><<set $npcs = {"npc_mercer": {"name": "Mercer", "portrait": "mercer.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_renner": {"name": "Renner", "portrait": "renner.jpg", "core_traits": {"relation": 0, "corruption": 0, "arousal": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_sol": {"name": "Sol", "portrait": "sol.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_bastien": {"name": "Bastien", "portrait": "bastien.jpg", "core_traits": {"relation": 0, "corruption": 0, "arousal": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_rue": {"name": "Rue", "portrait": "rue.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_marsh": {"name": "Marsh", "portrait": "marsh.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_kess": {"name": "Kess", "portrait": "kess.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_calloway": {"name": "Calloway", "portrait": "calloway.jpg", "core_traits": {"relation": 0, "corruption": 0, "arousal": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_vane": {"name": "Vane", "portrait": "vane.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_colm": {"name": "Colm", "portrait": "colm.jpg", "core_traits": {"relation": 0, "corruption": 0, "arousal": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_enns": {"name": "Enns", "portrait": "enns.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_voss": {"name": "Voss", "portrait": "voss.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_reyes": {"name": "Reyes", "portrait": "reyes.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_marr": {"name": "Marr", "portrait": "marr.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_cain": {"name": "Cain", "portrait": "cain.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_grier": {"name": "Grier", "portrait": "grier.jpg", "core_traits": {"relation": 0}, "flags": {}, "schedule": [], "relationship": ""}, "npc_sabin": {"name": "Sabin", "portrait": "sabin.jpg", "core_traits": {"relation": 0, "corruption": 0}, "flags": {}, "schedule": [], "relationship": ""}}>><<set $npc_interacted_today = {}>><<set $flags = {"game_started": true, "debug_mode": false}>><<set $flags_meta = {}>><<set $game_state = {
"current_canvas": "",
"visited_locations": [],
"visited_nodes": [],
"trigger_history": {},
"activity_trigger_history": {},
"visited_choices": {},
"active_modifiers": {},
"random_cooldowns": {},
"stage_advancement_log": {},
"media_cycle": {},
"quests": {},
"scheduled": [],
"fast_jobs": {
"xp": 0,
"cooldowns": {}
},
"bank": {
"balance": 0
},
"time_state": {
"current_hour": 20,
"current_minute": 0,
"current_day": "Monday",
"current_week": 1,
"day": 1
},
"origin_version": "0.2.1",
"origin_schema": 2879280211,
"last_version": "0.2.1",
"last_schema": 2879280211
}>><<nobr>>
<div class="game-intro">
<h1>Vesper</h1>
<p class="game-description">An owned half-human weapon who feels nothing but the sex she's used for. Inside Vance Dynamics she's the company's slave; outside, under a false face, she slips into powerful men's lives and drains them while they think they're using her — sent to hunt a rogue called Cain.</p>
<div class="developer-intro">
<p class="developer-about">We're a small indie studio crafting intimate, story-driven experiences. Every game is made with care, and your support helps us keep creating. If you enjoy our work, consider supporting us!</p>
<p class="support-link">👉 <a href="https://www.patreon.com/cw/nutgames844" target="_blank" rel="noopener">Support us on Patreon</a></p>
</div>
<div class="age-gate">
<p class="age-warning">⚠️ This game contains adult content intended for players 18 years of age or older.</p>
<div class="age-buttons">
[[✓ I am 18 or older - Enter Game->StartingCanvas_canvas_opening_office_Node_office]]
[[✗ I am NOT 18 or older->AgeBlocked]]
</div>
</div>
<div class="developer-footer">
<p class="developer-credit">Developed by <strong>NutGames</strong></p>
<p class="support-link">👉 <a href="https://www.patreon.com/cw/nutgames844" target="_blank" rel="noopener">Support us on Patreon</a></p>
</div>
</div>
<</nobr>><div class="blocked-page">
<h2>Access Denied</h2>
<p>This content is not available for you.</p>
<p>Please close this page.</p>
</div><!-- Time Display Widgets -->
<<widget "timeFormatted">>
<<set _hour to $game_state.time_state.current_hour>>
<<set _minute to $game_state.time_state.current_minute>>
<<set _displayHour to (_hour is 0 ? 12 : (_hour > 12 ? _hour - 12 : _hour))>>
<<set _ampm to (_hour < 12 ? "AM" : "PM")>>
<<set _minuteStr to (_minute < 10 ? "0" + _minute : _minute)>>
<<print _displayHour + ":" + _minuteStr + " " + _ampm>>
<</widget>>
<!-- Render a quest card: narrative line + (Pattern 2) auto-rendered 🎯 goal
block + 💡 tip line. Author tags state-pressure variants in the TOML and
the picker swaps which line fires; widget renders the chosen line, then
calls setup.computeHintGoal() to render the structured progress block from
the hint's stage condition (or canvas trigger conditions for branch-inside-
shell transitions). Game-level mechanics (decay rates, time costs, etc.)
live on :: TipsPage instead. -->
<<widget "renderStageHint">>
/* Pattern 2 (2026-05-01): accepts either a string (legacy callers) OR a
hint object {text, condition, tip, auto_goal, ...}. When passed an object
with auto_goal=true and a stage condition, the engine computes the
structured 🎯 goal block (bullets + live progress + 📍 location). When
passed a string OR a no-auto-goal object, falls back to splitting on
" — 🎯 " (legacy behavior) so existing games keep working unchanged. */
<<set _hintArg to $args[0]>>
<<set _hintObj to (typeof _hintArg === "object" && _hintArg !== null) ? _hintArg : null>>
<<set _hintText to _hintObj ? (_hintObj.text || "") : (_hintArg || "")>>
<<set _computedGoalHtml to _hintObj ? setup.computeHintGoal(_hintObj) : "">>
<<set _separator to " — 🎯 ">>
<<set _splitIdx to _hintText.indexOf(_separator)>>
<<if _computedGoalHtml>>
/* New path: structured auto-render. If text contains " — 🎯 ", strip the
manual goal portion (auto-render replaces it). */
<<if _splitIdx gt -1>>
<<set _flavor to _hintText.substring(0, _splitIdx)>>
<<else>>
<<set _flavor to _hintText>>
<</if>>
/* 2026-05-09: when State C "🔓 Ready" fires AND the hint defines
ready_text, swap flavor → ready_text. The author-supplied ready_text
replaces the regular text once all helper gates are met. */
<<if _hintObj && _hintObj.ready_text && setup._isHintReady(_hintObj)>>
<<set _flavor to _hintObj.ready_text>>
<</if>>
<div class="stage-hint-card">
<div class="stage-hint-flavor"><<print _flavor>></div>
<<print _computedGoalHtml>>
<<if _hintObj && _hintObj.tip>>
<div class="stage-hint-tip">💡 <<print _hintObj.tip>></div>
<</if>>
</div>
<<elseif _splitIdx gt -1>>
/* Legacy path: split on " — 🎯 " */
<<set _flavor to _hintText.substring(0, _splitIdx)>>
<<set _goal to _hintText.substring(_splitIdx + _separator.length)>>
<div class="stage-hint-card">
<div class="stage-hint-flavor"><<print _flavor>></div>
<div class="stage-hint-goal"><span class="stage-hint-target">🎯</span> <<print _goal>></div>
<<if _hintObj && _hintObj.tip>>
<div class="stage-hint-tip">💡 <<print _hintObj.tip>></div>
<</if>>
</div>
<<elseif _hintText>>
<div class="stage-hint-card">
<div class="stage-hint-flavor"><<print _hintText>></div>
</div>
<</if>>
<</widget>>
<<widget "timeDisplay">>
<div id="time-widget" class="time-display">
<div class="time-line">
<span id="time-display"><<timeFormatted>></span> | <span id="current-day"><<print $game_state.time_state.current_day>></span>
</div>
<div class="control-line">
<button class="time-btn" onclick="waitTime(10)" title="Advance 10 minutes">></button> | <button class="time-btn" onclick="waitTime(60)" title="Advance 1 hour">>></button> | <button class="time-btn" onclick="waitTime(1440)" title="Advance 1 day">>>>>></button>
</div>
</div>
<</widget>>
<<widget "sidebarItems">>
<<if setup.sidebar_items && setup.sidebar_items.length > 0>>
<div id="sidebar-items-widget">
<<for _si to 0; _si lt setup.sidebar_items.length; _si++>>
<<set _item to setup.sidebar_items[_si]>>
<<if _item.show_when and not setup.triggerConditionsSatisfied(_item.show_when)>>
<<continue>>
<</if>>
<<if _item.type is "countdown">>
<<set _daysLeft to _item.total_days - $game_state.time_state.day + 1>>
<div class="sidebar-item countdown-item" id="sidebar-countdown-<<print _si>>">
<<if _daysLeft gt 1>>
<<print _daysLeft + " " + _item.label>>
<<elseif _daysLeft is 1>>
<<print "Tomorrow is " + _item.label.replace("days until ", "")>>
<<elseif _daysLeft is 0>>
<<print "Today is " + _item.label.replace("days until ", "")>>
<<else>>
<<print _item.label.replace("days until ", "") + " has passed">>
<</if>>
</div>
<<elseif _item.type is "quest_next">>
/* The next STEP, on every screen — as opposed to trait_status_text, which is the
next STATE. A game shipped with four band strings in the sidebar and no verb, no
place and no person anywhere in the always-visible chrome: a player who never
opened the Quests page had no direction at all. Renders the same goal block as
the Quests page and the npc_panel "next" row (setup.renderQuestsGoalBlock), so
there is one implementation of what an objective looks like, not three.
`npc_id` picks that character's live card; omitted, it takes the live tier cards
in file order. `max` caps how many render (default 3). Terminal cards are
skipped: they carry no goals and would render a bare completion badge forever. */
<<if setup.renderQuestsGoalBlock and setup.evaluateGoals>>
<<set _qnCards to []>>
<<if _item.npc_id>>
<<set _qnOne to setup.pickQuestsCard(_item.npc_id)>>
<<if _qnOne>><<run _qnCards.push(_qnOne)>><</if>>
<<else>>
<<set _qnCards to setup.pickQuestsCards("story_goals") || []>>
<</if>>
<<set _qnMax to _item.max || 3>>
<<set _qnShown to 0>>
<<for _qi to 0; _qi lt _qnCards.length; _qi++>>
<<set _qnCard to _qnCards[_qi]>>
<<if _qnShown lt _qnMax and _qnCard and _qnCard.goals and _qnCard.goals.length gt 0 and not _qnCard.terminal>>
<<set _qnBlock to setup.renderQuestsGoalBlock(_qnCard, setup.evaluateGoals(_qnCard))>>
<<if _qnBlock>>
<<set _qnShown to _qnShown + 1>>
<div class="sidebar-item quest-next-item" id="sidebar-questnext-<<print _si>>-<<print _qi>>">
<<print _qnBlock>>
</div>
<</if>>
<</if>>
<</for>>
<</if>>
<<elseif _item.type is "trait_bar">>
<<set _tbOwner to _item.trait_owner || "player">>
<<set _tbKey to _item.trait>>
<<if _tbOwner is "npc">>
<<set _tbNpcId to _item.npc_id>>
<<set _tbNpcObj to (setup.npc_slug_map && setup.npc_slug_map[_tbNpcId]) ? State.variables.npcs[setup.npc_slug_map[_tbNpcId]] : (State.variables.npcs ? State.variables.npcs[_tbNpcId] : null)>>
<<set _traitVal to (_tbNpcObj && _tbNpcObj.core_traits) ? (_tbNpcObj.core_traits[_tbKey] || 0) : 0>>
<<else>>
<<set _traitVal to ($player && $player.core_traits) ? ($player.core_traits[_tbKey] || 0) : 0>>
<</if>>
<<set _traitMax to _item.max || 100>>
<<set _traitLabel to _item.label || _tbKey>>
<<set _traitPct to Math.max(0, Math.min(100, (_traitVal / _traitMax) * 100))>>
<<set _tbTier to "">>
<<if _item.color_tiers>>
<<for _ti to 0; _ti lt _item.color_tiers.length; _ti++>>
<<if _tbTier is "" and _traitPct lte (_item.color_tiers[_ti].up_to)>>
<<set _tbTier to _item.color_tiers[_ti].class>>
<</if>>
<</for>>
<</if>>
<<set _tbBandText to "">>
<<set _tbBandIcon to "">>
<<if _item.bands>>
<<for _bi to 0; _bi lt _item.bands.length; _bi++>>
<<set _bb to _item.bands[_bi]>>
<<if _tbBandText is "" and _bb.min isnot undefined and _bb.max isnot undefined and _traitVal gte _bb.min and _traitVal lte _bb.max>>
<<set _tbBandText to _bb.text>>
<<set _tbBandIcon to _bb.icon || "">>
<</if>>
<</for>>
<</if>>
<div class="sidebar-item trait-bar-item" id="sidebar-trait-bar-<<print _si>>">
<div class="trait-bar-label">
<<if _item.hide_value is true>>
<<print _traitLabel>>
<<else>>
<<print _traitLabel>>: <<print Math.floor(_traitVal)>> / <<print _traitMax>>
<</if>>
</div>
<div class="trait-bar-bg">
<div class="trait-bar-fill <<print _tbTier>>" style="width: <<print _traitPct>>%"></div>
<<if _tbBandText isnot "">>
<span class="trait-bar-band-text"><<print (_tbBandIcon ? _tbBandIcon + " " : "") + _tbBandText>></span>
<</if>>
</div>
</div>
<<elseif _item.type is "trait_status_text">>
<<set _tsOwner to _item.trait_owner || "player">>
<<set _tsKey to _item.trait>>
<<if _tsOwner is "npc">>
<<set _tsNpcId to _item.npc_id>>
<<set _tsNpcObj to (setup.npc_slug_map && setup.npc_slug_map[_tsNpcId]) ? State.variables.npcs[setup.npc_slug_map[_tsNpcId]] : (State.variables.npcs ? State.variables.npcs[_tsNpcId] : null)>>
<<set _tsVal to (_tsNpcObj && _tsNpcObj.core_traits) ? (_tsNpcObj.core_traits[_tsKey] || 0) : 0>>
<<else>>
<<set _tsVal to ($player && $player.core_traits) ? ($player.core_traits[_tsKey] || 0) : 0>>
<</if>>
<<set _tsText to "">>
<<set _tsIcon to "">>
<<if _item.bands>>
<<for _bi to 0; _bi lt _item.bands.length; _bi++>>
<<set _bb to _item.bands[_bi]>>
<<set _bMin to (_bb.min isnot undefined) ? _bb.min : -1e9>>
<<set _bMax to (_bb.max isnot undefined) ? _bb.max : 1e9>>
<<if _tsText is "" and _tsVal gte _bMin and _tsVal lte _bMax>>
<<set _tsText to _bb.text>>
<<set _tsIcon to _bb.icon || "">>
<</if>>
<</for>>
<</if>>
<<if _tsText isnot "">>
<div class="sidebar-item trait-status-text-item">
<<if _item.label>><div class="band-header"><<print _item.label>></div><</if>>
<span class="band-value"><<print (_tsIcon ? _tsIcon + " " : "") + _tsText>></span>
</div>
<</if>>
<<elseif _item.type is "trait_decay_warning">>
<!-- E20: render an amber warning when a decaying trait dropped today AND
is within 2.0 of its next stage gate. setup.getDecayWarnings() walks
the configured thresholds and compares last_day_snapshot vs current. -->
<<set _decayWarnings to setup.getDecayWarnings(_item.thresholds || {})>>
<<for _dw range _decayWarnings>>
<div class="sidebar-item trait-decay-warning-item">
⚠ <<print _dw.text>>
</div>
<</for>>
<<elseif _item.type is "passes">>
<div class="sidebar-item passes-item" id="sidebar-passes-<<print _si>>">
<<for _pi to 0; _pi lt setup.passes.length; _pi++>>
<<set _pass to setup.passes[_pi]>>
<<set _remaining to setup.getPassDaysRemaining(_pass.id)>>
<<if _remaining gte 0>>
<div class="pass-entry pass-active" id="pass-display-<<print _pass.id>>">
<<print (_pass.icon || "") + " " + _pass.name + ": " + _remaining + "d">>
</div>
<</if>>
<</for>>
</div>
<<elseif _item.type is "inventory">>
<div class="sidebar-item inventory-item" id="sidebar-inventory-<<print _si>>">
<<for _ii to 0; _ii lt setup.items.length; _ii++>>
<<set _itm to setup.items[_ii]>>
<<set _count to setup.getItemCount(_itm.id)>>
<<if _count gt 0>>
<div class="inventory-entry" id="inventory-display-<<print _itm.id>>">
<<print (_itm.icon || "") + " " + _itm.name + ": " + _count>>
</div>
<</if>>
<</for>>
</div>
<<elseif _item.type is "trait_words">>
<<set _twOwner to _item.trait_owner || "player">>
<<set _twKey to _item.trait>>
<<if _twOwner is "npc">>
<<set _twNpcId to _item.npc_id>>
<<set _twNpcObj to (setup.npc_slug_map && setup.npc_slug_map[_twNpcId]) ? State.variables.npcs[setup.npc_slug_map[_twNpcId]] : (State.variables.npcs ? State.variables.npcs[_twNpcId] : null)>>
<<set _twVal to (_twNpcObj && _twNpcObj.core_traits) ? (_twNpcObj.core_traits[_twKey] || 0) : 0>>
<<else>>
<<set _twVal to ($player && $player.core_traits) ? ($player.core_traits[_twKey] || 0) : 0>>
<</if>>
<<set _twMatched to "">>
<<set _twFound to false>>
<<if _item.bands>>
<<for _bi to 0; _bi lt _item.bands.length; _bi++>>
<<if not _twFound>>
<<set _twBand to _item.bands[_bi]>>
<<if _twBand.flag>>
<<if $flags and $flags[_twBand.flag] is true>>
<<set _twMatched to _twBand.text>>
<<set _twFound to true>>
<</if>>
<<elseif _twBand.min isnot undefined and _twBand.max isnot undefined>>
<<if _twVal gte _twBand.min and _twVal lte _twBand.max>>
<<set _twMatched to _twBand.text>>
<<set _twFound to true>>
<</if>>
<</if>>
<</if>>
<</for>>
<</if>>
<<if _twMatched isnot "">>
<div class="sidebar-item trait-words-item" id="sidebar-trait-words-<<print _si>>">
<<if _item.label>><div class="band-header"><<print _item.label>></div><</if>>
<span class="band-value"><<print _twMatched>></span>
</div>
<</if>>
<<elseif _item.type is "stage_label">>
/* E11: render "<prefix>: <stage label>" sourced from arc_stages.
Stage value lives in $player.core_traits[<slug>_stage] (integer).
Out-of-range value → highest-defined label. Undefined trait → just
the prefix with no colon. Empty arc_stages → renders nothing. */
<<set _slNpcId to _item.npc_id>>
<<set _slStages to (setup.npc_arc_stages && setup.npc_arc_stages[_slNpcId]) ? setup.npc_arc_stages[_slNpcId] : []>>
<<set _slRawStage to ($player && $player.core_traits) ? $player.core_traits[_slNpcId + "_stage"] : undefined>>
<<set _slPrefix to _item.prefix>>
<<if not _slPrefix>>
<<set _slUuid to (setup.npc_slug_map && setup.npc_slug_map[_slNpcId]) ? setup.npc_slug_map[_slNpcId] : _slNpcId>>
<<set _slNpcObj to State.variables.npcs ? State.variables.npcs[_slUuid] : null>>
<<set _slPrefix to _slNpcObj ? (_slNpcObj.name || _slNpcId) : _slNpcId>>
<</if>>
<<if _slStages.length gt 0 and _slRawStage isnot undefined>>
<<set _slIdx to Math.max(0, Math.min(Number(_slRawStage), _slStages.length - 1))>>
<<set _slLabel to _slStages[_slIdx]>>
<div class="sidebar-item stage-label-item" id="sidebar-stage-label-<<print _si>>">
<<print _slPrefix>>: <<print _slLabel>>
</div>
<<elseif _slPrefix>>
<div class="sidebar-item stage-label-item" id="sidebar-stage-label-<<print _si>>">
<<print _slPrefix>>
</div>
<</if>>
<<elseif _item.type is "npc_panel">>
/* RTS-style per-NPC card: name header + rows (arousal band / corruption / location).
Location uses setup.getNpcLocation — the SAME schedule source the Schedule page uses. */
<<set _npId to _item.npc_id>>
<<set _npObj to (setup.npc_slug_map && setup.npc_slug_map[_npId]) ? State.variables.npcs[setup.npc_slug_map[_npId]] : (State.variables.npcs ? State.variables.npcs[_npId] : null)>>
<<if _npObj>>
<<set _npRows to _item.rows || ["arousal"]>>
<<set _npHeader to _item.label || _npObj.name || _npId>>
<div class="sidebar-item npc-panel-item" id="sidebar-npc-panel-<<print _si>>">
<div class="npc-panel-header"><<print _npHeader>></div>
<<for _npri to 0; _npri lt _npRows.length; _npri++>>
<<set _npRow to _npRows[_npri]>>
<<if _npRow is "arousal">>
<<if not (setup.hiddenTraits && setup.hiddenTraits.includes("arousal"))>>
<<set _npAr to (_npObj.core_traits) ? (_npObj.core_traits.arousal || 0) : 0>>
<<set _npBands to _item.arousal_bands || [{"min":0,"max":0,"text":"❄️"},{"min":1,"max":1,"text":"🔥"},{"min":2,"max":2,"text":"🔥🔥"},{"min":3,"max":3,"text":"🔥🔥🔥"}]>>
<<set _npArText to "">>
<<for _nbi to 0; _nbi lt _npBands.length; _nbi++>>
<<set _nb to _npBands[_nbi]>>
<<if _npArText is "" and _nb.min isnot undefined and _nb.max isnot undefined and _npAr gte _nb.min and _npAr lte _nb.max>>
<<set _npArText to _nb.text>>
<</if>>
<</for>>
<div class="sidebar-row"><span class="sidebar-label">🔥 Arousal</span> <span class="sidebar-value"><<print _npArText>></span></div>
<</if>>
<<elseif _npRow is "corruption">>
<<if not (setup.hiddenTraits && setup.hiddenTraits.includes("corruption"))>>
<<set _npCorr to (_npObj.core_traits) ? (_npObj.core_traits.corruption || 0) : 0>>
<<set _npCorrOut to _npCorr>>
<<if _item.corruption_max_value isnot undefined and _npCorr gte _item.corruption_max_value>>
<<set _npCorrOut to (_item.corruption_max_label || "MAX")>>
<</if>>
<div class="sidebar-row"><span class="sidebar-label">🫦 Corruption</span> <span class="sidebar-value"><<print _npCorrOut>></span></div>
<</if>>
<<elseif _npRow is "location">>
<<set _npLoc to setup.getNpcLocation(_npId)>>
<<set _npLocName to _npLoc ? (setup._locNameFromUuid(_npLoc.location) || _npLoc.location) : (_item.away_label || "Away")>>
<div class="sidebar-row"><span class="sidebar-label">📍 Location</span> <span class="sidebar-value"><<print _npLocName>></span></div>
<<elseif _npRow is "next">>
/* Next-milestone block — EXACT Quests-page parity: reuses setup.renderQuestsGoalBlock, so
the card shows the same goal block as the Quests page — 🎯 To advance + ◯ live progress
(climbing) / 🔓 Ready + 📍 + 🕒 (ready) / ✓ Arc complete (terminal). No flavor/tip text. */
<<if setup.pickQuestsCard and setup.renderQuestsGoalBlock>>
<<set _npCard to setup.pickQuestsCard(_npId)>>
<<if _npCard>>
<<set _npGoalBlock to setup.renderQuestsGoalBlock(_npCard, setup.evaluateGoals(_npCard))>>
<<if _npGoalBlock>>
<div class="npc-panel-next"><<print _npGoalBlock>></div>
<</if>>
<</if>>
<</if>>
<</if>>
<</for>>
</div>
<</if>>
<</if>>
<</for>>
</div>
<</if>>
<</widget>>
<<widget "playerPortrait">>
<<if setup.player_portrait_enabled and setup.player_portrait>>
<<set _pimg to setup.getPlayerPortrait()>>
<<if _pimg>>
<div class="sidebar-player-portrait"><img @src="_pimg" @alt="$player.name" onerror="this.style.display='none';"></div>
<</if>>
<</if>>
<</widget>>
<<widget "activeModifiers">>
<<if $game_state && $game_state.active_modifiers && Object.keys($game_state.active_modifiers).length gt 0>>
<div id="sidebar-modifiers-widget" class="traits-display">
<div class="traits-header">Active Effects</div>
<<set _modKeys to Object.keys($game_state.active_modifiers)>>
<<for _mi to 0; _mi lt _modKeys.length; _mi++>>
<<set _mod to $game_state.active_modifiers[_modKeys[_mi]]>>
<<set _hoursLeft to (_mod.expires_day - $game_state.time_state.day) * 24 + (_mod.expires_hour - $game_state.time_state.current_hour)>>
<div class="modifier-badge"><<print _mod.name>> (<<print _hoursLeft>>h)</div>
<</for>>
</div>
<</if>>
<</widget>>
<<widget "inc">>
<<set _incTrait to $args[0]>>
<<set _incBy to ($args[1] != null) ? Number($args[1]) : 1>>
<<script>>setup.applyAndNotifyTrait("player", null, _incTrait, "add", _incBy, false, null);<</script>>
<</widget>>
<<widget "dec">>
<<set _decTrait to $args[0]>>
<<set _decBy to ($args[1] != null) ? Number($args[1]) : 1>>
<<script>>setup.applyAndNotifyTrait("player", null, _decTrait, "add", -_decBy, false, null);<</script>>
<</widget>>
<<widget "playerTraits">>
<div id="traits-widget" class="traits-display">
<div class="traits-header">Traits</div>
<<if $player and $player.core_traits and Object.keys($player.core_traits).length > 0>>
<<set _keys to Object.keys($player.core_traits).sort()>>
<ul class="traits-list">
<<for _i to 0; _i lt _keys.length; _i++>>
<<set _k to _keys[_i]>>
<<if setup.hiddenTraits && setup.hiddenTraits.includes(_k)>><<continue>><</if>>
<li class="trait-item">
<span class="trait-name"><<print _k>></span>
<span class="trait-value"><<print $player.core_traits[_k]>></span>
</li>
<</for>>
</ul>
<<else>>
<div class="no-traits">No traits</div>
<</if>>
<div class="traits-hint">Updates after each choice.</div>
</div>
<</widget>>
<<widget "playerFlags">>
<div id="flags-widget" class="traits-display">
<div class="traits-header">Flags</div>
<<if $flags and Object.keys($flags).length > 0>>
<<set _fkeys to Object.keys($flags).sort()>>
<ul class="traits-list">
<<for _j to 0; _j lt _fkeys.length; _j++>>
<<set _fk to _fkeys[_j]>>
<li class="trait-item">
<span class="trait-name"><<print _fk>></span>
<span class="trait-value"><<print $flags[_fk] ? '✔' : '✖'>></span>
</li>
<</for>>
</ul>
<<else>>
<div class="no-traits">No flags</div>
<</if>>
<div class="traits-hint">Set by choices and story logic.</div>
</div>
<</widget>>
<<widget "questsButton">>
<!-- Debug/legacy quest view - shows raw mechanics -->
<div id="quests-btn-widget">
<<if passage() isnot "QuestsPage">><<link "Quests" "QuestsPage">><</link>><<else>><span class="nav-row">Quests</span><</if>><span class="nav-i">📋</span>
</div>
<</widget>>
<<widget "missingMediaButton">>
<<if $flags.debug_mode>>
<div id="missing-media-btn-widget" style="margin-bottom:8px;">
<<if passage() isnot "MissingMediaPage">><<link "⚠️ Missing Media" "MissingMediaPage">><</link>><<else>>⚠️ Missing Media<</if>>
</div>
<</if>>
<</widget>>
<<widget "journalButton">>
<!-- Quests - active per-NPC quest cards -->
<div id="journal-btn-widget">
<<if passage() isnot "QuestsPage">><<link "Quests" "QuestsPage">><</link>><<else>><span class="nav-row">Quests</span><</if>><span class="nav-i">📋</span>
</div>
<</widget>>
<<widget "tipsButton">>
<!-- Tips - game-level mechanics surface; conditional on [ui.tips_page] authored -->
<<if setup.tips_page && setup.tips_page.content>>
<div id="tips-btn-widget">
<<if passage() isnot "TipsPage">><<link "Tips" "TipsPage">><</link>><<else>><span class="nav-row">Tips</span><</if>><span class="nav-i">💡</span>
</div>
<</if>>
<</widget>>
<<widget "statsButton">>
<div id="stats-btn-widget">
<<if passage() isnot "StatsPage">><<link "Stats" "StatsPage">><</link>><<else>><span class="nav-row">Stats</span><</if>><span class="nav-i">📊</span>
</div>
<</widget>>
<<widget "scheduleButton">>
<<set _npcsWithSchedules to setup.getNpcsWithSchedules()>>
<<set _soloActivities to setup.getSoloActivitiesForToday()>>
<<if _npcsWithSchedules.length > 0 || _soloActivities.length > 0>>
<div id="schedule-btn-widget">
<<if passage() isnot "SchedulePage">><<link "Schedules" "SchedulePage">><</link>><<else>><span class="nav-row">Schedules</span><</if>><span class="nav-i">📅</span>
</div>
<</if>>
<</widget>>
<<widget "patreonButton">>
<div id="patreon-btn-widget">
<a href="https://www.patreon.com/cw/nutgames844" target="_blank" rel="noopener" class="patreon-link">
<svg class="patreon-icon" viewBox="0 0 24 24" width="16" height="16">
<path fill="currentColor" d="M15.386.524c-4.764 0-8.64 3.876-8.64 8.64 0 4.75 3.876 8.613 8.64 8.613 4.75 0 8.614-3.864 8.614-8.613C24 4.4 20.136.524 15.386.524M.003 23.537h4.22V.524H.003"/>
</svg>
Support Us
</a>
</div>
<</widget>>
<<widget "flagsButton">>
<div id="flags-btn-widget">
<<if passage() isnot "FlagsPage">><<link "Flags" "FlagsPage">><</link>><<else>><span class="nav-row">Flags</span><</if>><span class="nav-i">🚩</span>
</div>
<</widget>>
<<widget "versionFooter">>
<div class="sidebar-version">v0.2.1 · 2026-09-10</div>
<</widget>><<missingMediaButton>>
<<timeDisplay>>
<<playerPortrait>>
<<sidebarItems>>
<<activeModifiers>>
<<journalButton>>
<<castButton>>
<<tipsButton>>
<<cheatButton>>
<<statsButton>>
<<scheduleButton>>
<<playerTraits>>
<<patreonButton>>
<<versionFooter>>
<style>
#time-widget {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 4px;
padding: 8px;
margin-bottom: 10px;
font-family: var(--theme-font-mono);
font-size: 14px;
line-height: 1.2;
color: var(--theme-text);
}
.time-line {
text-align: center;
margin-bottom: 4px;
font-weight: bold;
color: var(--theme-text-strong);
}
.control-line {
text-align: center;
font-size: 12px;
}
.time-btn {
background: var(--theme-surface-alt);
border: 1px solid var(--theme-border);
border-radius: 3px;
color: var(--theme-text-secondary);
cursor: pointer;
padding: 3px 6px;
font-size: 12px;
font-family: var(--theme-font-mono);
font-weight: bold;
}
.time-btn:hover {
background: var(--theme-border);
color: var(--theme-text-strong);
border-color: var(--theme-border);
}
#sidebar-items-widget {
margin-bottom: 8px;
}
.sidebar-item {
text-align: left; /* one type system across the rail — left, theme sans (was centered mono) */
padding: 6px 8px;
font-size: 13px;
line-height: 1.3;
}
.countdown-item {
background: var(--theme-warning-bg);
border: 1px solid var(--theme-warning);
border-radius: 4px;
color: var(--theme-warning-text);
font-weight: bold;
}
.hint-item {
background: var(--theme-success-bg);
border: 1px solid var(--theme-success);
border-radius: 4px;
color: var(--theme-success);
font-style: italic;
}
/* quest_next — the next STEP in the rail. Quieter than the hint card on purpose: it
is there on every screen, so it reads as chrome rather than as an alert. The inner
goal block reuses the Quests-page classes (.quests-goal / .quests-ready / .quests-where). */
.quest-next-item {
padding: 4px 8px;
border-left: 2px solid var(--theme-border);
margin-bottom: 4px;
}
#traits-widget {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 4px;
padding: 8px;
margin-top: 8px;
font-family: var(--theme-font-mono);
font-size: 13px;
color: var(--theme-text);
}
#flags-widget {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 4px;
padding: 8px;
margin-top: 8px;
font-family: var(--theme-font-mono);
font-size: 13px;
color: var(--theme-text);
}
.traits-header {
font-weight: bold;
margin-bottom: 6px;
}
.traits-list {
list-style: none;
padding-left: 0;
margin: 0;
}
.trait-item {
display: flex;
justify-content: space-between;
border-bottom: 1px dashed var(--theme-border);
padding: 2px 0;
}
.trait-name {
color: var(--theme-text-secondary);
}
.trait-value {
color: var(--theme-primary);
font-weight: bold;
}
.no-traits {
font-style: italic;
color: var(--theme-text-muted);
}
.traits-hint {
margin-top: 6px;
font-size: 11px;
color: var(--theme-text-muted);
}
#time-display, #current-day {
font-family: var(--theme-font-mono);
color: var(--theme-text-strong);
}
/* ===== Sidebar action buttons — ONE neutral pill family =====
Structure is carried by neutral surfaces; the accent is reserved for hover
(and .is-active). Replaces the old zoo: 4 tinted pills + 2 parchment-serif
journal/tips. All six now share one filled surface pill, left-aligned, muted
label, accent on hover, single 6px radius. */
/* ===== Sidebar action buttons — ONE neutral pill family =====
The link (or the current-page .nav-row span) FILLS the whole padded box, so
the ENTIRE box is clickable — not just the text. The icon overlays the right
edge with pointer-events:none, so clicks there pass through to the link beneath.
Structure in neutrals; accent reserved for hover. */
#phone-sidebar-btn,
#quests-btn-widget,
#journal-btn-widget,
#tips-btn-widget,
#cast-btn-widget,
#cheat-btn-widget,
#stats-btn-widget,
#schedule-btn-widget,
#flags-btn-widget {
position: relative; /* anchor the icon overlay + unread badge */
background: var(--theme-surface);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 6px;
margin: 8px 0 0 0; /* uniform 8px rhythm — same as the cards */
}
/* the clickable fill: <a> in nav state, .nav-row span on the current page */
#phone-sidebar-btn a,
#quests-btn-widget a, #journal-btn-widget a, #tips-btn-widget a, #cast-btn-widget a, #cheat-btn-widget a, #stats-btn-widget a, #schedule-btn-widget a, #flags-btn-widget a,
#quests-btn-widget .nav-row, #journal-btn-widget .nav-row, #tips-btn-widget .nav-row, #cast-btn-widget .nav-row, #cheat-btn-widget .nav-row, #stats-btn-widget .nav-row, #schedule-btn-widget .nav-row, #flags-btn-widget .nav-row {
display: block;
width: 100%;
box-sizing: border-box;
padding: 8px 30px 8px 10px; /* padded fill → whole box clickable; right room for the icon */
text-align: left; /* override the #ui-bar default center */
color: var(--theme-text-muted);
text-decoration: none;
font-weight: 600;
}
#phone-sidebar-btn a:hover,
#quests-btn-widget a:hover, #journal-btn-widget a:hover, #tips-btn-widget a:hover, #cast-btn-widget a:hover, #cheat-btn-widget a:hover, #stats-btn-widget a:hover, #schedule-btn-widget a:hover, #flags-btn-widget a:hover {
color: var(--theme-accent);
text-decoration: none;
}
.nav-i { /* right-edge icon overlay; clicks pass through to the link */
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
/* Sidebar spacing is margin-driven, not <br>-driven (kill stray empty-widget breaks). */
#story-caption br { display: none; }
/* State-reactive player portrait (opt-in) — the TOP-MOST sidebar image. The theme's
global img rule does not reach sidebar imgs, so without this the raw image renders at
natural size and overflows the narrow sidebar (you'd see a background edge, not the
face). Constrain to the sidebar width and frame it as a 3:4 portrait crop centred a bit
high, so a square or tall source shows the face/torso rather than the legs/background. */
.sidebar-player-portrait {
margin: 0 0 12px 0;
text-align: center;
}
.sidebar-player-portrait img {
display: block;
width: 100%;
max-width: 100%;
height: auto;
aspect-ratio: 3 / 4;
object-fit: cover;
object-position: 50% 18%;
border-radius: 6px;
}
/* Patreon Button in Sidebar */
#patreon-btn-widget {
margin: 15px 0 0 0;
padding: 15px 0 0 0;
border-top: 1px solid #444;
text-align: center;
}
/* Version / release-date footer at the very bottom of the sidebar */
.sidebar-version {
margin-top: 8px;
font-size: 11px;
color: var(--theme-text-muted, #8a8a8a);
text-align: center;
}
/* Cheat page rows. Flat and mechanical by design — this page is read as a list of
levers, not as prose, so the fiction lives on the container and the rows stay legible. */
.cheat-intro {
margin-bottom: 12px;
color: var(--theme-text-muted, #8a8a8a);
font-size: 13px;
}
.cheat-row {
padding: 7px 0;
border-bottom: 1px solid var(--theme-border, #2a2a2a);
}
.cheat-row:last-of-type { border-bottom: none; }
.cheat-hint, .cheat-at-cap {
margin-top: 2px;
color: var(--theme-text-muted, #8a8a8a);
font-size: 12px;
}
.cheat-row-maxed {
font-weight: 600;
opacity: 0.5;
}
/* Code entry. The box is the whole surface for a player with no code, so it is
sized to be obviously the thing to use rather than tucked in a corner. */
.cheat-entry {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.cheat-entry input[type="text"] {
flex: 1 1 160px;
min-width: 0;
padding: 6px 8px;
border: 1px solid var(--theme-border, #3a3a3a);
border-radius: 4px;
background: var(--theme-surface-alt, #1a1a1a);
color: var(--theme-text, #e8e8e8);
text-transform: uppercase;
letter-spacing: 0.08em;
}
#cheat-reply { flex: 1 1 100%; }
.cheat-reply-bad {
color: var(--theme-danger, #d06a6a);
font-size: 12px;
}
/* The join line is this page's only advertising: for a player with no code it is the
sole thing on the page that tells them what the box is for. */
.cheat-join {
margin-bottom: 14px;
padding-bottom: 12px;
border-bottom: 1px solid var(--theme-border, #2a2a2a);
color: var(--theme-text-muted, #8a8a8a);
font-size: 12px;
}
/* Version chip — the release a player matches against their guide, since codes are
scoped per release. Rides inside .sidebar-version and the cheat page's heading. */
.build-badge {
display: inline-block;
padding: 0 5px;
border: 1px solid var(--theme-border, #3a3a3a);
border-radius: 3px;
font-size: 10px;
letter-spacing: 0.02em;
white-space: nowrap;
color: var(--theme-text-muted, #8a8a8a);
}
/* Reduce gap between StoryCaption and Save/Restart menu */
#story-caption {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
#menu-story {
margin-top: 8px !important;
}
.patreon-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
background: #f96854;
color: #fff !important;
border-radius: 4px;
text-decoration: none;
font-size: 0.9em;
font-weight: bold;
}
.patreon-link:hover {
background: #e85a47;
text-decoration: none !important;
}
.patreon-icon {
flex-shrink: 0;
}
.stats-card {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 6px;
padding: 12px;
margin-bottom: 12px;
}
.stats-name {
font-weight: bold;
font-size: 1.2em;
color: var(--theme-text);
margin-bottom: 8px;
border-bottom: 1px solid var(--theme-border);
padding-bottom: 6px;
}
.stats-traits {
margin-top: 8px;
}
.stats-trait-item {
display: flex;
justify-content: space-between;
padding: 4px 8px;
border-bottom: 1px dashed var(--theme-border);
color: var(--theme-text-strong);
}
.stats-trait-value {
font-weight: bold;
color: var(--theme-primary);
}
/* Story Arc Help Page Styles */
.chapter-context {
background: linear-gradient(135deg, var(--theme-surface) 0%, var(--theme-surface-alt) 100%);
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.chapter-name {
font-size: 1.1em;
color: var(--theme-text);
font-weight: bold;
}
.chapter-mood {
font-size: 0.9em;
color: var(--theme-text-muted);
font-style: italic;
}
.available-section h3 {
font-size: 1em;
color: var(--theme-text-secondary);
margin: 0 0 10px 0;
border-bottom: 1px solid var(--theme-border);
padding-bottom: 6px;
}
.help-card {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 6px;
padding: 12px 16px;
margin-bottom: 10px;
}
.node-name {
font-weight: bold;
color: var(--theme-text);
}
.node-hint {
color: var(--theme-text-muted);
font-size: 0.9em;
margin-top: 4px;
}
.narrative-hint {
background: var(--theme-warning-bg);
border: 1px solid var(--theme-warning);
border-radius: 6px;
padding: 12px;
margin: 16px 0;
}
.narrative-hint p {
margin: 0;
color: var(--theme-warning-text);
}
.progress-summary {
text-align: center;
color: var(--theme-text-muted);
font-size: 0.9em;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid var(--theme-border);
}
.no-quests-msg {
font-style: italic;
color: var(--theme-text-muted);
padding: 10px;
}
/* Quest Page - Simplified One Activity Per NPC */
.npc-section {
margin-bottom: 20px;
padding: 16px;
background: linear-gradient(135deg, var(--theme-surface) 0%, var(--theme-surface-alt) 100%);
border-radius: 10px;
border: 1px solid var(--theme-border);
}
.npc-name {
font-size: 1.2em;
color: var(--theme-text);
margin: 0 0 12px 0;
border-bottom: 2px solid var(--theme-primary);
padding-bottom: 8px;
font-weight: 600;
}
.guide-hint {
font-size: 0.85em;
color: #f0c040;
font-style: italic;
}
.quest-available {
color: var(--theme-success);
font-weight: 500;
padding: 10px 14px;
background: rgba(40, 167, 69, 0.1);
border-radius: 6px;
border-left: 4px solid var(--theme-success);
}
/* E16: Stage hint two-part card. Flavor on top, goal block below. */
.stage-hint-card {
padding: 12px 14px;
background: rgba(40, 167, 69, 0.08);
border-radius: 6px;
border-left: 4px solid var(--theme-success);
margin: 8px 0;
}
.stage-hint-flavor {
font-style: italic;
opacity: 0.75;
margin-bottom: 10px;
font-size: 0.95em;
}
/* Pattern 2 (2026-05-01) — auto-rendered structured goal block */
.stage-hint-goal-header {
font-weight: 600;
margin-bottom: 6px;
color: var(--theme-success);
}
.stage-hint-goal ul {
list-style: none;
padding-left: 8px;
margin: 4px 0;
}
.stage-hint-goal li {
padding: 3px 0;
font-family: var(--theme-font-mono, 'Courier New', monospace);
font-size: 0.92em;
line-height: 1.4;
}
.stage-hint-met {
color: var(--theme-success);
font-weight: 600;
display: inline-block;
width: 1.2em;
}
.stage-hint-unmet {
color: var(--theme-text-muted);
display: inline-block;
width: 1.2em;
}
.stage-hint-met-row {
color: var(--theme-success);
opacity: 0.9;
}
.stage-hint-unmet-row {
color: var(--theme-text);
opacity: 0.85;
}
.stage-hint-progress {
color: var(--theme-text-muted);
margin-left: 6px;
font-size: 0.88em;
}
.stage-hint-where {
margin-top: 8px;
font-size: 0.9em;
opacity: 0.85;
color: var(--theme-text);
font-style: normal;
}
.stage-hint-tip {
margin-top: 10px;
padding: 6px 10px;
background: rgba(255, 193, 7, 0.08);
border-left: 3px solid var(--theme-warning, #ffc107);
border-radius: 3px;
font-size: 0.9em;
line-height: 1.45;
opacity: 0.92;
}
.stage-hint-path {
margin-top: 6px;
padding: 6px 8px;
border-left: 2px solid var(--theme-accent, #4ecdc4);
background: rgba(78, 205, 196, 0.05);
}
.stage-hint-path strong {
color: var(--theme-accent, #4ecdc4);
font-size: 0.92em;
}
/* Pattern 2 (2026-05-04) — Ready frame: shown when every gate of a stage
transition's trigger evaluates true. Replaces the gate checklist with a
compact "go here, this time window" surface. */
.stage-hint-ready {
color: var(--theme-success);
font-weight: 700;
letter-spacing: 0.02em;
}
/* Pattern 2 (2026-05-09) — Arc-complete frame: shown when an author marks
a hint template `arc_complete = true` (terminal stage in the slice).
Quieter than Ready — reads as closure rather than an action prompt. */
.stage-hint-arc-complete {
color: var(--theme-text-muted, #888);
font-weight: 600;
font-style: italic;
letter-spacing: 0.02em;
}
.quest-locked {
color: var(--theme-warning-text);
font-weight: 500;
padding: 10px 14px;
background: rgba(255, 193, 7, 0.15);
border-radius: 6px;
border-left: 4px solid var(--theme-warning);
}
.quest-conditions {
color: var(--theme-danger);
font-weight: 500;
padding: 10px 14px;
background: rgba(220, 53, 69, 0.1);
border-radius: 6px;
border-left: 4px solid var(--theme-danger);
}
.quest-waiting {
color: var(--theme-warning-text);
font-weight: 500;
padding: 10px 14px;
background: rgba(255, 193, 7, 0.15);
border-radius: 6px;
border-left: 4px solid var(--theme-warning);
font-style: italic;
}
.dev-canvas-info {
background: var(--theme-primary);
color: white;
padding: 6px 10px;
border-radius: 4px;
margin-bottom: 10px;
font-size: 11px;
font-family: var(--theme-font-mono);
}
.quest-complete {
color: var(--theme-success);
font-style: italic;
padding: 10px 14px;
text-align: center;
}
.no-quests {
color: var(--theme-text-muted);
font-style: italic;
padding: 12px;
text-align: center;
}
/* Tips page — wrapped inside an .npc-section card frame on the page itself.
Section headers (<h3>) use the same accent treatment as .npc-name dividers
in the Quests page so the two pages read as the same family. */
.tips-page-content {
line-height: 1.55;
color: var(--theme-text);
}
.tips-page-content h3 {
font-size: 1.05em;
color: var(--theme-text);
margin: 18px 0 8px;
padding-bottom: 6px;
border-bottom: 2px solid var(--theme-primary);
font-weight: 600;
}
.tips-page-content h3:first-child {
margin-top: 0;
}
.tips-page-content p {
margin: 6px 0;
}
.tips-page-content strong {
color: var(--theme-text);
font-weight: 600;
}
/* Trait Requirement Link */
.trait-requirement-link {
color: var(--theme-danger);
text-decoration: underline;
cursor: pointer;
}
.trait-requirement-link:hover {
color: var(--theme-danger);
}
/* Trait Activities Modal Overlay */
.trait-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
/* Modal Container */
.trait-modal {
background: #fff;
border-radius: 12px;
max-width: 400px;
width: 90%;
max-height: 80vh;
overflow: hidden;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}
.trait-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
background: var(--theme-surface);
border-bottom: 1px solid var(--theme-border);
}
.trait-modal-header h3 {
margin: 0;
font-size: 1.1em;
color: #333;
}
.trait-modal-close {
font-size: 24px;
cursor: pointer;
color: var(--theme-text-muted);
line-height: 1;
}
.trait-modal-close:hover {
color: #333;
}
.trait-modal-progress {
padding: 12px 20px;
background: rgba(220, 53, 69, 0.1);
color: var(--theme-danger);
font-weight: 500;
text-align: center;
}
.trait-modal-body {
padding: 16px 20px;
max-height: 50vh;
overflow-y: auto;
}
/* Activity List */
.trait-activity-list {
list-style: none;
padding: 0;
margin: 0;
}
.trait-activity-list li {
padding: 12px;
border-bottom: 1px solid var(--theme-border);
}
.trait-activity-list li:last-child {
border-bottom: none;
}
.activity-name {
font-weight: 600;
color: #333;
}
.activity-bonus {
float: right;
color: var(--theme-success);
font-weight: 500;
}
.activity-hint {
margin-top: 4px;
color: var(--theme-text-muted);
font-size: 0.9em;
clear: both;
}
/* Effect Toast Notification */
.effect-toast {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.85);
color: var(--theme-success);
padding: 10px 20px;
border-radius: 6px;
font-size: 14px;
z-index: 10002;
white-space: nowrap;
}
/* S4 — Threshold-publisher toast (gated_action). Distinct from the green
effect-toast: amber/warning palette, italic, allows wrapping for the longer
in-character explanation, slightly higher z-index so it doesn't get hidden
behind the success toast when both fire on the same click. */
.effect-toast.notify-warning {
background: rgba(255, 152, 0, 0.95);
color: #1a1a1a;
border-left: 4px solid #c66900;
font-style: italic;
white-space: normal;
max-width: 480px;
text-align: left;
line-height: 1.4;
z-index: 10003;
}
/* Game Intro - Top Left Aligned */
.game-intro {
text-align: left;
}
/* Age Gate Section */
.age-gate {
background: var(--theme-warning-bg);
border: 1px solid var(--theme-warning);
border-radius: 8px;
padding: 20px;
margin: 20px 0;
text-align: center;
}
.age-warning {
font-weight: bold;
color: var(--theme-warning-text);
margin-bottom: 15px;
}
.age-buttons {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
}
/* Developer Intro Section (above age gate) */
.developer-intro {
text-align: left;
color: var(--theme-text-muted);
margin: 20px 0;
}
/* Developer Footer Section (below age gate) */
.developer-footer {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid var(--theme-border);
text-align: center;
color: var(--theme-text-muted);
font-size: 0.9em;
}
.developer-intro a,
.developer-footer a {
color: #f96854;
text-decoration: none;
}
.developer-intro a:hover,
.developer-footer a:hover {
text-decoration: underline;
}
.developer-about {
line-height: 1.5;
margin: 10px 0;
}
.support-link {
margin-top: 8px;
}
.developer-footer .support-link {
font-weight: bold;
}
/* Age Blocked Page */
.blocked-page {
text-align: center;
padding: 50px;
color: var(--theme-danger);
background: var(--theme-danger-bg);
border-radius: 8px;
margin: 50px auto;
max-width: 400px;
}
/* Override SugarCube default vertical centering */
#story {
align-items: flex-start !important;
justify-content: flex-start !important;
padding-top: 1em !important;
}
.passage {
margin-top: 0 !important;
padding-top: 0 !important;
}
/* New/Unvisited Canvas Highlight */
.new-canvas a {
color: var(--theme-success) !important;
font-weight: 600;
}
.new-canvas a::before {
content: "✨ ";
}
/* Unlocked conditional choice highlight (in passages) */
.unlocked-choice a, .unlocked-choice .link-internal {
color: var(--theme-warning) !important;
font-weight: 600;
}
.unlocked-choice a::before, .unlocked-choice .link-internal::before {
content: "🔓 ";
}
/* Locked choice (visible but not available — Mode A) */
.locked-choice {
color: var(--theme-text-muted);
font-style: italic;
cursor: not-allowed;
opacity: 0.6;
display: inline-block;
padding: 2px 0;
}
.locked-choice::before {
content: "🔒 ";
}
/* Rejection choice (clickable but leads to rejection — Mode B) */
.rejection-choice a, .rejection-choice .link-internal {
color: #b45555 !important;
font-style: italic;
}
.rejection-choice a::before, .rejection-choice .link-internal::before {
content: "⚠️ ";
}
/* Active modifier sidebar badge */
.modifier-badge {
display: inline-block;
background: rgba(168, 85, 247, 0.15);
color: #c084fc;
border: 1px solid rgba(168, 85, 247, 0.3);
border-radius: 12px;
padding: 2px 10px;
font-size: 0.8em;
font-style: italic;
margin: 2px 0;
}
/* Unlocked choice canvas link highlight (in location activity list) */
.unlocked-choice-canvas a {
color: var(--theme-warning) !important;
font-weight: 600;
}
.unlocked-choice-canvas a::before {
content: "🔓 ";
}
/* Navigation New Content Indicator */
.nav-new {
color: var(--theme-warning);
font-weight: bold;
font-size: 1.1em;
}
/* Navigation NPC Portrait Indicator */
.nav-npc-portrait {
width: 24px;
height: 24px;
border-radius: 50%;
object-fit: cover;
vertical-align: middle;
margin-left: 4px;
border: 2px solid var(--theme-border);
}
/* ===============================================
VISUAL NAVIGATION GRID
=============================================== */
.location-nav-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin: 8px 0;
}
@media (min-width: 768px) {
.location-nav-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 1024px) {
.location-nav-grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Location Card */
.location-card {
display: flex;
flex-direction: column;
background: #2a2a2a;
border-radius: 8px;
overflow: hidden;
text-decoration: none !important;
color: inherit !important;
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
}
.location-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Card Image Area (5:2 aspect ratio - more compact) */
.location-card-image {
width: 100%;
padding-bottom: 40%; /* 5:2 ratio */
background-size: cover;
background-position: center;
position: relative;
background-color: #1a1a1a;
}
/* Placeholder silhouette for locations without images */
.location-card-placeholder {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #2d2d3a 0%, #1a1a2a 100%);
}
.location-card-placeholder svg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60%;
height: 60%;
opacity: 0.5;
}
/* Card Content Area */
.location-card-content {
padding: 6px 8px;
display: flex;
flex-direction: column;
gap: 2px;
}
.location-card-name {
font-weight: 600;
font-size: 0.9em;
line-height: 1.2;
color: var(--theme-text);
}
/* Indicators Row */
.location-card-indicators {
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
}
/* NEW badge (replaces ! indicator in visual mode) */
.nav-new-badge {
background: var(--theme-warning);
color: #000;
font-size: 0.65em;
font-weight: bold;
padding: 2px 5px;
border-radius: 3px;
text-transform: uppercase;
}
/* NPC portrait badges (smaller version for cards) */
.nav-npc-badge {
width: 20px;
height: 20px;
border-radius: 50%;
object-fit: cover;
border: 1px solid var(--theme-text-muted);
}
/* Locked destination card (lock-as-prose): shown but not clickable, with the reason */
.location-card-locked {
opacity: 0.6;
cursor: not-allowed;
filter: grayscale(0.4);
}
.location-card-locked .location-card-image {
filter: grayscale(0.6) brightness(0.85);
}
.nav-locked-reason {
font-size: 0.7em;
line-height: 1.25;
color: var(--theme-text-muted);
font-style: italic;
margin-top: 2px;
}
/* Text-mode locked link */
.nav-link-locked {
color: var(--theme-text-muted);
font-style: italic;
}
/* Travel-cost tag on a nav destination (neutral, informational) */
.nav-cost-tag {
font-size: 0.65em;
color: var(--theme-text-muted);
background: var(--theme-surface);
border: 1px solid var(--theme-border, rgba(255,255,255,0.12));
border-radius: 3px;
padding: 1px 5px;
margin-left: 4px;
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
/* Exit Links Section (text-only, below grid) */
.location-nav-exits {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #444;
}
.location-nav-exits a {
color: var(--theme-text-muted);
}
.location-nav-exits a:hover {
color: #fff;
}
/* ===== NPC Portrait System (Location Interaction) ===== */
/* Grid of clickable NPC portraits shown at locations */
.location-npcs {
display: flex;
gap: 1.5rem;
justify-content: center;
padding: 1.5rem 0;
flex-wrap: wrap;
}
.npc-portrait-card {
text-align: center;
cursor: pointer;
transition: transform 0.2s ease;
position: relative;
}
.npc-portrait-card:hover {
transform: scale(1.08);
}
.npc-portrait-link {
text-decoration: none !important;
color: inherit !important;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
}
.npc-portrait-img {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
border: 3px solid var(--theme-text-muted);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.npc-portrait-card:hover .npc-portrait-img {
border-color: var(--theme-border);
box-shadow: 0 0 12px rgba(200, 200, 200, 0.2);
}
/* Initial letter fallback for missing portraits */
.npc-portrait-placeholder {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, #3a3a4a 0%, #2a2a3a 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
font-weight: 600;
color: var(--theme-border);
border: 3px solid var(--theme-text-muted);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.npc-portrait-card:hover .npc-portrait-placeholder {
border-color: var(--theme-border);
box-shadow: 0 0 12px rgba(200, 200, 200, 0.2);
}
.npc-portrait-name {
display: block;
font-size: 0.85rem;
color: var(--theme-text-muted);
line-height: 1.2;
}
/* .npc-badge kept as base class for .npc-cost-badge (cost-blocked portraits).
NEW/unlocked portrait border + badge classes removed 2026-05-25. */
.npc-badge {
position: absolute;
top: -4px;
right: -4px;
font-size: 0.6rem;
font-weight: bold;
padding: 2px 5px;
border-radius: 8px;
text-transform: uppercase;
}
/* Solo activity buttons (activities with no NPC) */
.location-solo-activities {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #333;
}
.solo-activity-btn {
display: inline-block;
padding: 0.4rem 1rem;
margin: 0.3rem 0;
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 4px;
color: var(--theme-text) !important;
text-decoration: none !important;
transition: background 0.2s ease;
}
.solo-activity-btn:hover {
background: var(--theme-surface-alt);
color: var(--theme-text-strong) !important;
}
/* ===== Cost-blocked states ===== */
/* Blocked NPC portraits (greyed out) */
.npc-portrait-blocked .npc-portrait-img,
.npc-portrait-blocked .npc-portrait-placeholder {
filter: grayscale(70%) brightness(0.6);
border-color: #444;
}
.npc-portrait-blocked .npc-portrait-name {
color: var(--theme-text-muted);
}
.npc-portrait-blocked:hover {
transform: scale(1.04);
}
/* Cost badge on portraits */
.npc-cost-badge {
background: var(--theme-danger);
color: #fff;
font-size: 0.55rem;
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
padding: 1px 6px;
border-radius: 8px;
top: auto;
right: auto;
}
/* Blocked solo activities */
.solo-activity-blocked {
opacity: 0.5;
}
.solo-activity-blocked:hover {
opacity: 0.7;
}
.solo-cost-tag {
font-size: 0.75em;
color: var(--theme-danger);
}
/* E21 — author-opt-in cooldown entry. Non-clickable dimmed text. */
.solo-activity-cooldown {
display: inline-block;
padding: 4px 8px;
margin-bottom: 2px;
color: var(--theme-border);
font-style: normal;
font-size: 0.9em;
opacity: 0.65;
}
.solo-activity-cooldown em {
font-size: 0.85em;
opacity: 0.85;
}
/* Cost-blocked passage message */
.cost-blocked-message {
text-align: center;
padding: 2rem;
color: var(--theme-text-muted);
font-style: italic;
}
.cost-blocked-message p {
margin-bottom: 1rem;
}
/* ===== E20: Sidebar decay warning ===== */
.trait-decay-warning-item {
margin-top: 0.5rem;
padding: 6px 10px;
background: rgba(255, 193, 7, 0.18);
border-left: 3px solid var(--theme-warning);
border-radius: 4px;
color: var(--theme-warning-text);
font-size: 0.78rem;
line-height: 1.35;
}
/* ===== Sidebar band cards (trait_words / trait_status_text / trait_bar) =====
ONE card language. Structure is carried by NEUTRAL surfaces + spacing; the
accent is RESERVED for signal (hover / .is-active), never the resting stripe.
trait_words is the HERO stat (corruption / identity) — raised surface + larger
value so it anchors the top of the rail instead of reading as a peer card. */
.trait-words-item,
.trait-status-text-item,
.trait-bar-item {
text-align: left;
margin-top: 0.5rem;
padding: 8px 10px;
background: var(--theme-surface);
border: 1px solid rgba(255, 255, 255, 0.07); /* hairline — survives across tiers, clears the eye (the old #333 border was ~1.3:1, invisible) */
border-left: 3px solid rgba(255, 255, 255, 0.10); /* neutral at rest */
border-radius: 6px;
color: var(--theme-text);
font-size: 0.78rem;
line-height: 1.35;
}
/* HERO: the identity word-state (corruption) reads as the top-of-rail anchor. */
.trait-words-item {
background: var(--theme-surface-hover); /* +0.08 lighter — the existing 'raised' tier */
}
.trait-words-item .band-value {
font-size: 1.05rem;
line-height: 1.25;
}
/* The accent/semantic left-stripe is a SCARCE SIGNAL (active / urgent / locked),
not decoration — a row earns it; toggled by emitting the class on that item. */
.sidebar-item.is-active { border-left-color: var(--theme-accent); }
.sidebar-item.is-urgent { border-left-color: var(--theme-warning); }
.sidebar-item.is-locked { border-left-color: var(--theme-danger); }
/* the label, rendered as a compact card header (matches .npc-panel-header) */
.band-header {
color: var(--theme-text-muted);
font-weight: bold;
font-size: 11px;
letter-spacing: 0.06em;
text-transform: uppercase;
margin-bottom: 4px;
}
/* the value line (word / status text) */
.band-value {
color: var(--theme-text-strong);
font-weight: 600;
font-size: 0.86rem;
font-variant-numeric: tabular-nums lining-nums; /* columns don't jitter as values change */
}
/* ===== trait_bar — banded word over a flat fill bar ===== */
.trait-bar-label {
color: var(--theme-text-muted);
font-weight: bold;
font-size: 11px;
letter-spacing: 0.06em;
text-transform: uppercase;
margin-bottom: 5px;
}
.trait-bar-bg {
height: 8px;
background: var(--theme-surface-alt);
border-radius: 6px;
overflow: hidden;
position: relative;
}
.trait-bar-fill {
height: 100%;
background: var(--theme-accent);
border-radius: 6px;
transition: width 0.3s ease;
}
/* Banded mode: when a trait_bar's band-text overlay is rendered, the bg grows
to fit the overlay text. Gated via :has() so non-banded bars stay at 8px. */
.trait-bar-bg:has(.trait-bar-band-text) {
height: 26px;
border-radius: 6px;
}
.trait-bar-band-text {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 9px;
font-size: 0.78rem;
font-weight: 600;
color: var(--theme-text-strong);
font-variant-numeric: tabular-nums lining-nums;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
pointer-events: none;
z-index: 2;
white-space: nowrap;
}
/* Built-in value-tier fills — flat & matte (set a tier class via color_tiers).
Authors can override by shipping their own .trait-bar-fill.<class> rules. */
.trait-bar-fill.low {
background: #3b82c4;
}
.trait-bar-fill.medium {
background: #d98a3a;
}
.trait-bar-fill.high {
background: #d65a5a;
}
/* NPC panel card (npc_panel sidebar item) — RTS House-card: header strip + label/value rows */
.npc-panel-item {
text-align: left;
padding: 0;
margin-top: 0.5rem;
background: var(--theme-surface);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 6px;
overflow: hidden;
}
.npc-panel-header {
padding: 5px 8px;
background: var(--theme-surface-alt);
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
color: var(--theme-text-strong);
font-weight: bold;
font-size: 12px;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.npc-panel-item .sidebar-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 4px 8px;
font-size: 12px;
}
.npc-panel-item .sidebar-label {
color: var(--theme-text-muted);
white-space: nowrap;
}
.npc-panel-item .sidebar-value {
color: var(--theme-text-strong);
font-weight: 500;
text-align: right;
font-variant-numeric: tabular-nums lining-nums;
}
.npc-panel-next {
margin-top: 4px;
padding: 4px 8px 2px;
border-top: 1px solid rgba(255, 255, 255, 0.07);
}
/* the inner goal block reuses the Quests-page classes (.quests-goal/.quests-ready/.quests-where) */
/* Dev Mode Controls */
.dev-adj-btn {
background: var(--theme-text-muted);
color: white;
border: none;
border-radius: 3px;
width: 20px;
height: 20px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
padding: 0;
line-height: 1;
vertical-align: middle;
}
.dev-adj-btn:hover {
background: var(--theme-text-muted);
}
.trait-controls {
display: flex;
align-items: center;
gap: 4px;
}
.trait-controls .trait-value {
min-width: 24px;
text-align: center;
}
/* Portrait System */
.portrait {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: var(--theme-surface-alt);
display: flex;
align-items: center;
justify-content: center;
}
.portrait img {
width: 100%;
height: 100%;
object-fit: cover;
}
.portrait-placeholder svg {
width: 70%;
height: 70%;
}
/* Dialog Block — the face floats, and ONE text flow runs beside and under it.
Two earlier shapes were built and rejected in the same session, and the reasons are
worth keeping because both look reasonable on paper:
· a fixed-width speaker COLUMN — every box's text started at the same x, which was
the point, but the identity stack drove the height: a one-line box measured 120px
carrying 28px of text, so 77% of it was not text.
· the same column FLOATED — height dropped to 68px, but a fixed column still holds
its width whether the name needs it or not, which left a wide empty gap between
"husband" and the line the character was actually saying.
The gap was the complaint, and a column of any kind causes it. So there is no column:
the name, the role and the speech are one flow. Whichever of name/role comes last takes
a colon and the speech continues straight from it, wrapping beside the portrait and then
under it.
┌──────┐ Dorn
│ face │ husband: Back Friday. Late.
└──────┘ ...and the rest wraps under the face.
⚠️ FLOAT, NOT FLEX. Neither flex nor grid can make text wrap around a box; only a float
can. `display: block` here is the mechanism, not a style choice.
⚠️ The 480px breakpoint the floated column needed is GONE, and should not come back.
It existed because a fixed column plus a face ate 142px of a 360px screen and left a
14-character first line. With no column there is nothing to reserve, so the phone and
the laptop want the same rules. */
.dialog-block {
/* ⚠️ THE FACE IS DERIVED FROM THE IDENTITY, NOT THE OTHER WAY ROUND. The label beside
the portrait is two rows — the name's own row, and the row the role SHARES with the
first words of the speech — so its height is `name-row + leading` no matter what the
portrait does. Sizing the rows as a fraction of the face made the label overflow it
by 8-9px, and could not be fixed by changing the fraction: solving
`0.7*F + leading <= F` needs `F >= leading / 0.3`, which at a 28px leading is a 93px
portrait. Deriving the face from the rows makes `identity == face` true by
construction, at any font size. */
--dlg-lead: 1.5em;
--dlg-name-row: 1.35em;
--dlg-face: calc(var(--dlg-name-row) + var(--dlg-lead));
display: block;
margin: 10px 0;
padding: 10px;
border-radius: 8px;
color: var(--theme-text);
}
/* ⚠️ MANDATORY. A block containing only floats collapses to zero height, and it looks
fine until a box has a short line. `::after` rather than `overflow: hidden`: same
effect on height, no risk of clipping a rounded portrait. */
.dialog-block::after {
content: "";
display: block;
clear: both;
}
/* Scoped to the dialog block: the global `.portrait` rule above is 40px and still serves
the thought bubble and every other caller. */
.dialog-block > .portrait {
float: left;
width: var(--dlg-face);
height: var(--dlg-face);
margin: 0 10px 4px 0;
}
.dialog-player {
border-left: 4px solid var(--theme-primary);
background: var(--theme-primary-bg);
}
.dialog-player strong {
color: var(--theme-primary);
}
.dialog-npc {
border-left: 4px solid var(--theme-text-muted);
background: var(--theme-surface);
}
.dialog-npc strong {
color: var(--theme-text-secondary);
}
/* Normal flow on purpose — this is what wraps around the floated face, and it now holds
the name and role as well as the speech.
⚠️ `overflow-wrap: anywhere` stays: one long unbroken string would otherwise overflow
and give the phone a horizontal scrollbar, invisible at desktop width. */
.dialog-content {
overflow-wrap: anywhere;
line-height: var(--dlg-lead);
}
/* The name takes a row of its own ONLY when a role follows it, so the role can sit under
it. With no role there is nothing to sit under, and `dlg-inline` keeps the name on the
speech's own line. */
/* The name takes a row of its own ONLY when a role follows it, and the two are
proportioned to the FACE — 70% of its height for the name, 30% for the role — so the
identity reads as one unit standing the same height as the portrait beside it. Both
are derived from `--dlg-face` rather than fixed, so they track it at every viewport.
The font sizes carry floors: 24% of a 36px phone face is 8.6px, which is too small to
read, so `max()` holds the role at 9px there. */
.dialog-content strong {
display: block;
height: var(--dlg-name-row);
line-height: var(--dlg-name-row);
font-size: 1.05em;
}
/* ⚠️ The role-less case shares its line with the speech, so it must NOT inherit the 70%
line box above — that would stretch the line the character is speaking on. It keeps
the surrounding leading instead. */
.dialog-content strong.dlg-inline {
display: inline;
height: auto;
line-height: inherit;
font-size: 1em;
}
/* F10 — the short label under a speaker's name. Quieter than the name, because it is a
label and must not compete with the line the character is actually saying. INLINE, so
the speech continues from it rather than starting a new row.
⚠️ Its 30% is the height of the ROLE's own inline box. The line it sits on also holds
the first words of the speech, and a line box is as tall as its tallest inline box, so
that line renders at the speech's leading — the 30% governs the label, not the row. */
.dialog-role {
display: inline;
font-size: max(9px, 0.62em);
line-height: inherit;
color: var(--theme-text-muted, #8a8a8a);
}
/* The colon lives in CSS so the role and name TEXT stay clean for anything that reads
them. It goes on whichever of the two is last. */
.dialog-role::after,
.dialog-content strong.dlg-inline::after {
content: ":";
}
/* Thought Bubble Block (S8) — interior monologue, paired with cascade beats */
.thought-bubble {
display: flex;
align-items: center;
gap: 12px;
margin: 8px 0 8px 24px;
padding: 8px 12px;
border-radius: 12px;
background: var(--theme-surface-alt);
color: var(--theme-text-secondary);
font-style: italic;
border-left: 4px dashed var(--theme-text-secondary);
}
.thought-bubble-player {
border-left-color: var(--theme-accent, var(--theme-text-primary));
}
.thought-bubble-content {
flex: 1;
}
/* Cascade Advance Links (S7) — visual cue distinct from choice exits */
.macro-linkreplace a {
display: inline-block;
margin-top: 1px;
padding: 2px 8px;
background: var(--theme-surface);
border: 1px solid var(--theme-accent, var(--theme-text-primary));
border-radius: 6px;
color: var(--theme-accent, var(--theme-text-primary));
text-decoration: none;
font-size: 0.95em;
line-height: 1.3;
}
.macro-linkreplace a:hover {
background: var(--theme-accent, var(--theme-text-primary));
color: var(--theme-bg, #fff);
}
/* Engine "no exits satisfied" dev diagnostic (2026-05-06) — fires when a
canvas's all-conditional exit_block has zero satisfied choices. Visible
only when $flags.debug_mode is true. The console.warn fires regardless. */
.engine-diag-no-exits {
background: #2a0a0a;
border: 2px solid #c0392b;
padding: 12px 16px;
margin: 16px 0;
border-radius: 4px;
color: #f5d8d6;
font-family: var(--theme-font-mono, monospace);
font-size: 12px;
}
.engine-diag-header {
font-weight: bold;
color: #ff6b6b;
margin-bottom: 8px;
}
.engine-diag-hint {
color: #f0c0bd;
margin-bottom: 12px;
font-style: italic;
}
.engine-diag-choice {
background: #1a0505;
padding: 8px 12px;
margin: 8px 0;
border-left: 3px solid #c0392b;
}
.engine-diag-choice-text { font-weight: bold; }
.engine-diag-choice-logic { font-size: 11px; color: #d4a8a4; margin-bottom: 4px; }
.engine-diag-items { margin: 4px 0 0 0; padding-left: 16px; list-style: none; }
.engine-diag-items li { margin: 2px 0; }
.engine-diag-pass { color: #6dcf6d; }
.engine-diag-fail { color: #ff8a85; }
/* Stats Card Portrait (larger) */
.stats-portrait {
width: 80px;
height: 100px;
border-radius: 8px;
overflow: hidden;
background: var(--theme-surface-alt);
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.stats-portrait img {
width: 100%;
height: 100%;
object-fit: cover;
}
.stats-portrait svg {
width: 60%;
height: 60%;
}
/* Stats Card with Portrait Layout */
.stats-card-with-portrait {
display: flex;
gap: 12px;
align-items: flex-start;
}
.stats-info {
flex: 1;
min-width: 0;
}
/* Wardrobe Page */
.wardrobe-page {
margin: 12px 0;
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 10px;
padding: 16px;
}
.wardrobe-table {
width: 100%;
border-collapse: collapse;
}
.wardrobe-row {
border-bottom: 1px solid var(--theme-border);
}
.wardrobe-row:last-child {
border-bottom: none;
}
.wardrobe-row-disabled {
opacity: 0.45;
}
.wardrobe-slot-label {
padding: 12px 8px;
font-weight: 700;
color: #333;
width: 90px;
vertical-align: middle;
font-size: 0.85em;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.wardrobe-slot-items {
padding: 10px 4px;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.wardrobe-item {
position: relative;
width: 76px;
height: 76px;
border: 2px solid var(--theme-border);
border-radius: 8px;
cursor: pointer;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.wardrobe-item:hover {
border-color: var(--theme-text-muted);
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.12);
}
.wardrobe-item-equipped {
border-color: var(--theme-success);
background: var(--theme-success-bg);
box-shadow: 0 0 0 2px rgba(40, 167, 69, 0.25);
}
.wardrobe-item-equipped:hover {
border-color: var(--theme-success);
}
.wardrobe-item-locked {
opacity: 0.5;
cursor: not-allowed;
filter: grayscale(50%);
}
.wardrobe-item-locked:hover {
transform: none;
box-shadow: none;
border-color: var(--theme-border);
}
.wardrobe-item-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wardrobe-item-text {
font-size: 0.8em;
text-align: center;
padding: 6px;
word-break: break-word;
color: #333;
line-height: 1.2;
}
.wardrobe-badge-equipped {
position: absolute;
top: 2px;
right: 2px;
background: var(--theme-success);
color: #fff;
font-size: 11px;
width: 18px;
height: 18px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.wardrobe-badge-locked {
position: absolute;
bottom: 2px;
right: 2px;
font-size: 13px;
}
.wardrobe-unequip-btn {
background: none;
border: 1px solid var(--theme-text-muted);
color: var(--theme-text-muted);
width: 28px;
height: 28px;
border-radius: 50%;
cursor: pointer;
font-size: 16px;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
transition: background 0.15s, color 0.15s;
}
.wardrobe-unequip-btn:hover {
background: var(--theme-danger);
border-color: var(--theme-danger);
color: #fff;
}
.wardrobe-disabled-hint,
.wardrobe-empty-hint {
color: var(--theme-text-muted);
font-style: italic;
font-size: 0.85em;
}
.entry-blocked {
color: var(--theme-danger);
font-weight: 500;
}
.entry-requirements {
color: var(--theme-warning-text);
background: var(--theme-warning-bg);
padding: 8px 12px;
border-radius: 6px;
font-size: 0.9em;
}
.entry-blocked-narrative {
font-style: italic;
color: var(--theme-text-muted);
line-height: 1.6;
margin: 12px 0;
}
#wardrobe-btn-widget button {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
color: #333;
padding: 6px 12px;
border-radius: 6px;
cursor: pointer;
width: 100%;
font-size: 0.95em;
margin: 4px 0;
}
#wardrobe-btn-widget button:hover {
background: var(--theme-surface-alt);
border-color: var(--theme-border);
}
/* Shop page styles */
.shop-page {
margin: 12px 0;
}
.shop-money {
background: var(--theme-success-bg);
border: 1px solid var(--theme-success);
border-radius: 8px;
padding: 10px 16px;
font-size: 1.05em;
font-weight: 600;
color: var(--theme-success);
margin-bottom: 16px;
display: inline-block;
}
.shop-tier {
margin-bottom: 20px;
border: 1px solid var(--theme-border);
border-radius: 10px;
overflow: hidden;
background: var(--theme-surface);
}
.shop-tier-locked {
opacity: 0.55;
}
.shop-tier-header {
background: var(--theme-text-strong);
color: #fff;
padding: 10px 16px;
font-weight: 700;
font-size: 0.95em;
display: flex;
justify-content: space-between;
align-items: center;
}
.shop-tier-locked .shop-tier-header {
background: var(--theme-text-muted);
}
.shop-tier-req {
font-weight: 400;
font-size: 0.85em;
opacity: 0.8;
}
.shop-tier-locked-msg {
padding: 12px 16px;
color: var(--theme-warning-text);
background: var(--theme-warning-bg);
font-style: italic;
font-size: 0.9em;
text-align: center;
}
.shop-items {
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
}
.shop-slot-group {
margin-bottom: 4px;
}
.shop-slot-label {
font-weight: 700;
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--theme-text-secondary);
padding: 4px 0;
border-bottom: 1px solid var(--theme-surface-alt);
margin-bottom: 6px;
}
.shop-slot-items {
display: flex;
flex-direction: column;
gap: 6px;
}
.shop-item {
display: flex;
align-items: center;
gap: 12px;
background: #fff;
border: 1px solid var(--theme-border);
border-radius: 8px;
padding: 10px 14px;
transition: border-color 0.15s;
}
.shop-item-thumb {
width: 56px;
height: 56px;
border: 2px solid var(--theme-border);
border-radius: 8px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: var(--theme-surface);
flex-shrink: 0;
}
.shop-item-thumb-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.shop-item-thumb-text {
font-size: 0.7em;
text-align: center;
padding: 4px;
word-break: break-word;
color: var(--theme-text-muted);
line-height: 1.2;
}
.shop-item:hover {
border-color: var(--theme-border);
}
.shop-item-owned {
border-color: var(--theme-success);
background: var(--theme-success-bg);
}
.shop-item-unaffordable {
opacity: 0.55;
}
.shop-item-info {
display: flex;
flex-direction: column;
gap: 2px;
flex: 1;
min-width: 0;
}
.shop-item-name {
font-weight: 600;
color: var(--theme-text);
font-size: 0.95em;
}
.shop-item-action {
display: flex;
align-items: center;
gap: 10px;
}
.shop-item-price {
font-weight: 600;
color: var(--theme-text-secondary);
font-size: 0.95em;
}
.shop-item-owned-badge {
color: var(--theme-success);
font-weight: 600;
font-size: 0.9em;
}
.shop-item-cant-afford {
color: var(--theme-danger);
font-size: 0.85em;
font-style: italic;
}
.shop-buy-btn {
background: var(--theme-primary);
color: #fff;
border: none;
padding: 6px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 0.9em;
font-weight: 600;
transition: background 0.15s;
}
.shop-buy-btn:hover {
background: var(--theme-primary);
}
/* Rent page styles */
.rent-title {
color: var(--theme-bg);
margin-bottom: 16px;
font-size: 1.4em;
}
.rent-choices {
margin: 16px 0;
display: flex;
flex-direction: column;
gap: 8px;
}
.rent-choices a {
display: block;
padding: 10px 16px;
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 6px;
color: var(--theme-text);
text-decoration: none;
font-weight: 500;
transition: background 0.15s, border-color 0.15s;
}
.rent-choices a:hover {
background: var(--theme-surface-alt);
border-color: var(--theme-border);
}
.rent-balance {
margin-top: 12px;
padding: 8px 12px;
background: rgba(0,0,0,0.04);
border-radius: 6px;
font-size: 0.95em;
}
.game-over-text {
text-align: center;
font-size: 1.5em;
font-weight: bold;
color: var(--theme-danger);
margin: 20px 0;
letter-spacing: 2px;
}
</style><<widget "renderQuestsCard">>
<<set _card to $args[0]>>
<<if _card>>
<<set _goalState to setup.evaluateGoals(_card)>>
<<set _flavor to (_goalState.allMet && _card.ready_text) ? _card.ready_text : _card.text>>
<<set _goalBlock to setup.renderQuestsGoalBlock(_card, _goalState)>>
<div class="quests-card">
<div class="quests-flavor"><<print _flavor>></div>
<<if _goalBlock>><<print _goalBlock>><</if>>
<<if _card.tip>><div class="quests-tip">💡 <<print _card.tip>></div><</if>>
</div>
<</if>>
<</widget>><<nobr>>
<h2>What's Next</h2>
/* PRD 48 — Quests Engine V2 page. One card per arc NPC + Story Goals
section. Picker swaps cards as state crosses; goal-block frame swaps
from 🎯 (climbing) → 🔓 (ready) → ✓ (terminal) automatically. */
<<set _goals = setup.pickQuestsCards("story_goals")>>
<<if _goals.length > 0>>
<div class="quests-section">
<h3>Story Goals</h3>
<<for _g range _goals>><<renderQuestsCard _g>><</for>>
</div>
<</if>>
/* The NPC sections come from the CARDS, not from setup.help_data.npcs. help_data.npcs is
populated only by canvases carrying targetType="npc" trait effects (_build_help_data), so an
NPC with a full quest ladder but no stat bumps — one whose arc runs on player counters — was
silently absent and its cards never rendered (Vesper's Colm: 4 cards, 0 renders). quests_cards
IS the source of truth for who has cards, and pickQuestsCard() matches card.npc_id directly,
so no slug/uuid translation is needed and this behaves the same in --use-db builds. */
<<set _allCards = setup.quests_cards || []>>
<<set _hidden = setup.hiddenNpcs || {}>>
<<set _slugMap = setup.npc_slug_map || {}>>
<<set _npcSlugs = []>>
<<for _c range _allCards>>
<<if _c && _c.npc_id && _npcSlugs.indexOf(_c.npc_id) === -1>>
/* hiddenNpcs is UUID-keyed (hidden_npcs_map); check both forms so hidden_from_ui still
suppresses a section whichever build mode this is. */
<<if !_hidden[_c.npc_id] && !_hidden[_slugMap[_c.npc_id]]>>
<<run _npcSlugs.push(_c.npc_id)>>
<</if>>
<</if>>
<</for>>
<<set _rendered = 0>>
<<for _slug range _npcSlugs>>
<<set _card = setup.pickQuestsCard(_slug)>>
<<if _card>>
<<set _nid = _slugMap[_slug] || _slug>>
<<set _rendered = _rendered + 1>>
<div class="quests-section">
<h3><<print ($npcs[_nid] && $npcs[_nid].name) || ($npcs[_slug] && $npcs[_slug].name) || _slug.replace("npc_", "")>></h3>
<<renderQuestsCard _card>>
</div>
<</if>>
<</for>>
/* "did we draw a card", not "does help_data list anybody" — the old test could leave a bare
Story-Goals heading with nothing under it. */
<<if _goals.length === 0 && _rendered === 0>>
<div class="no-quests">No active quests.</div>
<</if>>
<</nobr>>
<<link "← Back">><<run setup.smartBack()>><</link>><<nobr>>
<<set _tp = setup.tips_page || {}>>
<h2><<print _tp.title || "Tips">></h2>
<div class="npc-section">
<div class="tips-page-content">
<<print _tp.content || "No tips available.">>
</div>
</div>
<</nobr>>
<<link "← Back">><<run setup.smartBack()>><</link>><<set _position = setup.detectStoryPosition()>>
<<set _hint = setup.generateNarrativeHint()>>
<div class="journal-container">
<div class="journal-header">
<<if _position.current_chapter>>
<h2 class="journal-chapter-title"><<print _position.current_chapter.name>></h2>
<<if _position.current_chapter.mood>>
<div class="journal-chapter-mood <<print _position.current_chapter.mood>>">
<<print _position.current_chapter.description || "">>
</div>
<</if>>
<<else>>
<h2 class="journal-chapter-title">Your Story</h2>
<</if>>
<<if _position.progress_percent > 0>>
<div class="journal-progress">
<div class="journal-progress-bar">
<div class="journal-progress-fill" style="width: <<print _position.progress_percent>>%;"></div>
</div>
</div>
<</if>>
</div>
<!-- Memories (completed story moments) -->
<<if _position.completed_nodes.length > 0>>
<div class="journal-section">
<div class="journal-section-title">Memories</div>
<<for _i, _node range _position.completed_nodes>>
<div class="journal-memory <<if _node.is_milestone>>milestone<</if>>">
<div class="journal-memory-title"><<print _node.name>></div>
<<if _node.journal_entry>>
<<print _node.journal_entry>>
<</if>>
</div>
<</for>>
</div>
<</if>>
<!-- Active story threads (groups in progress) -->
<<if _position.active_groups.length > 0>>
<<set _incompleteGroups = _position.active_groups.filter(function(g) { return !g.isComplete && g.completed > 0; })>>
<<if _incompleteGroups.length > 0>>
<div class="journal-section">
<div class="journal-section-title">Unfolding</div>
<<for _i, _group range _incompleteGroups>>
<div class="journal-group">
<div class="journal-group-name"><<print _group.name>></div>
<div class="journal-group-progress">
<<print _group.description>>
</div>
</div>
<</for>>
</div>
<</if>>
<</if>>
<!-- Relationship states (NPC emotions) -->
<<if Object.keys($npcs).length > 0>>
<div class="journal-section">
<div class="journal-section-title">Connections</div>
<<for _npcId range Object.keys($npcs)>>
<<set _state = setup.interpretNpcState(_npcId)>>
<<if _state.npc_name>>
<div class="journal-npc">
<div class="journal-npc-name"><<print _state.npc_name>></div>
<div class="journal-npc-emotion"><<print _state.description>></div>
<<if _state.relationship_summary && _state.relationship_summary !== _state.description>>
<div class="journal-npc-summary"><<print _state.relationship_summary>></div>
<</if>>
</div>
<</if>>
<</for>>
</div>
<</if>>
<!-- Subtle narrative hint (only when needed) -->
<<if _hint.hint_type !== "none" && _hint.text>>
<div class="journal-hint <<print _hint.hint_type>>">
<<print _hint.text>>
</div>
<</if>>
<!-- Empty state -->
<<if _position.completed_nodes.length === 0 && Object.keys($npcs).length === 0>>
<div class="journal-empty">
Your story is just beginning...
</div>
<</if>>
<div class="journal-back-link">
[[Return to your story->Navigation]]
</div>
</div><<nobr>>
<h2>All Stats</h2>
<!-- Player Stats -->
<div class="stats-card stats-card-with-portrait">
<div class="stats-portrait">
<<if $player.portrait>>
<img @src="'./videos/' + $player.portrait" @alt="$player.name" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';">
<<else>>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>
<</if>>
</div>
<div class="stats-info">
<div class="stats-name">You (<<print $player.name>>)</div>
<div class="stats-traits">
<<if $player && $player.core_traits && Object.keys($player.core_traits).length > 0>>
<<for _tk, _tv range $player.core_traits>>
<<if setup.hiddenTraits && setup.hiddenTraits.includes(_tk)>><<continue>><</if>>
<div class="stats-trait-item">
<span><<print _tk>></span>
<span class="stats-trait-value"><<print _tv>></span>
</div>
<</for>>
<<else>>
<em>No traits</em>
<</if>>
</div>
</div>
</div>
<!-- NPC Stats -->
<<if Object.keys($npcs).length > 0>>
<<for _npcId, _npc range $npcs>>
<<if (setup.hiddenNpcs && setup.hiddenNpcs[_npcId])>><<continue>><</if>>
<div class="stats-card stats-card-with-portrait">
<div class="stats-portrait">
<<if _npc.portrait>>
<img @src="'./videos/' + _npc.portrait" @alt="_npc.name" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';">
<<else>>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>
<</if>>
</div>
<div class="stats-info">
<div class="stats-name"><<print _npc.name>></div>
<div class="stats-traits">
<<if _npc.core_traits && Object.keys(_npc.core_traits).length > 0>>
<<for _tk, _tv range _npc.core_traits>>
<<if setup.hiddenTraits && setup.hiddenTraits.includes(_tk)>><<continue>><</if>>
<div class="stats-trait-item">
<span><<print _tk>></span>
<span class="stats-trait-value"><<print _tv>></span>
</div>
<</for>>
<<else>>
<em>No traits</em>
<</if>>
</div>
</div>
</div>
<</for>>
<<else>>
<p><em>No NPCs found.</em></p>
<</if>>
<</nobr>>
<<link "← Back">><<run setup.smartBack()>><</link>><<nobr>>
<h2>Change Clothes</h2>
<<= setup.renderWardrobePage()>>
<</nobr>>
<div id="wardrobe-warning" style="display:none; color:#ff6b6b; margin:10px 0; padding:8px; border:1px solid #ff6b6b; border-radius:4px;"></div>
<<link "← Back">><<script>>
var dest = State.variables.last_game_passage || "Navigation";
var clothingMsg = setup.checkLocationClothing(dest);
if (clothingMsg) {
var el = document.getElementById('wardrobe-warning');
if (el) { el.innerHTML = clothingMsg; el.style.display = 'block'; }
} else {
setup.smartBack();
}
<</script>><</link>><h2>Not Dressed for This</h2>
<p><<print State.variables._clothing_block_message || "You need to put on more clothes.">></p>
<div class="clothing-block-choices">
<<link "Change clothes">><<script>>
State.variables.last_game_passage = State.variables._clothing_block_destination;
Engine.play("WardrobePage");
<</script>><</link>>
<br>
<<link "Go back">><<script>>
Engine.play(State.variables.last_game_passage || "Navigation");
<</script>><</link>>
</div><!-- LOCK-AWARENESS (2026-08-11). The Schedules page is a GUIDANCE surface: it is the only screen that
publishes NPC hours, so the player uses it to decide where to walk. Schedule rows carry no conditions
by design — the resolver reads exactly five keys and drops the rest — so a row keeps pointing at a
location long after the story seals it, and getNpcLocation happily resolves "NOW" to a building the
player can no longer enter. Measured on vesper: after the Act-1a close it advertised Mercer as NOW at
his penthouse for 15 hours of every 24, and Calloway and Vane at Vance Securities, all three sealed by
the same flag. That is worse than saying nothing, because the player walks there.
The fix is on the PAGE, never on the rows: navDestUnlocked() is a pure entry_conditions check on the
location (no current-location dependency, no side effects), so it answers "can she get in right now"
for any slug. Locked rows are muted and show navDestBlockedReason() instead of the activity, and the
NOW badge and its activity line are suppressed entirely rather than naming a door that will not open. -->
<<nobr>>
<<set _currentDay to $game_state.time_state.current_day>>
<<set _todayIndex to ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"].indexOf(_currentDay)>>
<h2>📅 Weekly Schedule</h2>
<p class="current-time">Today is <<print _currentDay>> · <<print setup.formatTime($game_state.time_state.current_hour, $game_state.time_state.current_minute)>></p>
<<set _npcsWithSchedules to setup.getNpcsWithSchedules()>>
<<if _npcsWithSchedules.length === 0>>
<p><em>No NPCs have schedules defined.</em></p>
<<else>>
<<for _npcInfo range _npcsWithSchedules>>
<<set _npcId to _npcInfo.id>>
<<set _npcName to _npcInfo.name>>
<<set _currentLoc to setup.getNpcLocation(_npcId)>>
<<set _allSchedules to setup.getNpcAllSchedulesSorted(_npcId)>>
<div class="npc-section">
<h3 class="npc-name">
<<print _npcName>>
<<set _nowSlug to _currentLoc ? (setup._getLocUuidToSlug()[_currentLoc.location] || _currentLoc.location) : "">>
<<set _nowOpen to _currentLoc ? setup.navDestUnlocked(_nowSlug) : false>>
<<if _currentLoc and _nowOpen>>
<<set _locName to (setup.locations[_currentLoc.location] && setup.locations[_currentLoc.location].name) || setup._locNameFromUuid(_currentLoc.location) || _currentLoc.location>>
<span class="now-badge">NOW: <<print _locName>></span>
<</if>>
</h3>
<<if _currentLoc and _nowOpen and _currentLoc.activity>>
<div class="current-activity">"<<print _currentLoc.activity>>"</div>
<</if>>
<<if _allSchedules.length === 0>>
<p><em>No schedule entries.</em></p>
<<else>>
<table class="schedule-table">
<thead><tr><th>Time</th><th>Location</th><th>Activity</th><th>Days</th></tr></thead>
<tbody>
<<for _sch range _allSchedules>>
<<set _schSlug to _sch.location_slug || _sch.location>>
<<set _schOpen to setup.navDestUnlocked(_schSlug)>>
<<set _isCurrent to _schOpen && setup.isCurrentTimeSlot(_sch.start_time, _sch.end_time) && setup._weekdayMatches(_sch.weekdays, _todayIndex)>>
<<set _rowClass to _isCurrent ? "current-slot" : (_schOpen ? "" : "locked-slot")>>
<<set _schLocName to (setup.locations[_sch.location] && setup.locations[_sch.location].name) || _sch.location>>
<!-- @class, NOT class="<<print>>". SugarCube does not evaluate macros inside a raw HTML attribute — it
emits them verbatim, so the row shipped with the literal string as its class and `.current-slot`
never matched anything. Found 2026-08-11 while adding `.locked-slot`; the attribute directive is the
same one the choice renderer already uses for `unlocked-choice`. -->
<tr @class="_rowClass">
<td><<if _isCurrent>>▶ <</if>><<print _sch.start_time>>-<<print _sch.end_time || "?">></td>
<td><<print _schLocName>></td>
<td><<if _schOpen>><<print _sch.activity>><<else>><span class="locked-slot-reason"><<print setup.navDestBlockedReason(_schSlug)>></span><</if>></td>
<td><<print setup.renderWeekdayBadges(_sch.weekdays, _todayIndex)>></td>
</tr>
<</for>>
</tbody>
</table>
<</if>>
</div>
<</for>>
<</if>>
<<set _soloActivities to setup.getSoloActivitiesAllSchedules()>>
<<if _soloActivities.length > 0>>
<div class="npc-section solo-activities-section">
<h3 class="npc-name">Your Activities</h3>
<table class="schedule-table">
<thead><tr><th>Time</th><th>Location</th><th>Activity</th><th>Days</th></tr></thead>
<tbody>
<<for _act range _soloActivities>>
<<set _rowClass to _act.isCurrent ? "current-slot" : "">>
<!-- @class for the same reason as the NPC table above — the literal-attribute bug applied here too. -->
<tr @class="_rowClass">
<td><<if _act.isCurrent>>▶ <</if>><<print _act.startTime>>-<<print _act.endTime || "?">></td>
<td><<print _act.locationName>></td>
<td><<print _act.name>></td>
<td><<print setup.renderWeekdayBadges(_act.weekdays, _todayIndex)>></td>
</tr>
<</for>>
</tbody>
</table>
</div>
<</if>>
<<link "← Back">><<run setup.smartBack()>><</link>>
<</nobr>>
<style>
.current-time {
color: var(--theme-text-strong);
font-size: 0.9em;
margin: 0 0 10px 0;
}
.now-badge {
background: var(--theme-success);
color: white;
padding: 3px 8px;
border-radius: 10px;
font-size: 0.75em;
font-weight: bold;
margin-left: 10px;
vertical-align: middle;
}
.current-activity {
color: var(--theme-text-muted);
font-style: italic;
margin-bottom: 8px;
font-size: 0.85em;
}
.schedule-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85em;
color: var(--theme-text);
}
.schedule-table th {
text-align: left;
padding: 4px 8px;
background: var(--theme-surface);
border-bottom: 2px solid var(--theme-border);
color: var(--theme-text-strong);
font-weight: 600;
}
.schedule-table td {
padding: 4px 8px;
border-bottom: 1px solid var(--theme-border);
color: var(--theme-text-strong);
vertical-align: middle;
}
.schedule-table tr.current-slot {
background: var(--theme-warning-bg);
font-weight: 500;
}
.schedule-table tr.current-slot td:first-child {
color: var(--theme-warning-text);
}
/* A schedule row whose location the player cannot currently enter. Muted rather than hidden: a row that
vanishes reads as "he has no schedule there", where a muted one reads as "that door is shut for now",
which is the truth and is what a returning player needs. Never carries the ▶ current marker. */
.schedule-table tr.locked-slot {
opacity: 0.55;
}
.schedule-table tr.locked-slot .locked-slot-reason {
font-style: italic;
opacity: 0.85;
}
.solo-activities-section {
margin-top: 18px;
}
.weekday-badges {
display: inline-flex;
flex-wrap: wrap;
gap: 3px;
}
.weekday-badge {
display: inline-block;
padding: 1px 6px;
border-radius: 8px;
font-size: 0.72em;
font-weight: 600;
background: var(--theme-surface);
color: var(--theme-text-muted);
border: 1px solid var(--theme-border);
}
.weekday-badge.weekday-today {
background: var(--theme-primary);
color: white;
border-color: var(--theme-primary);
}
.weekday-badge.weekday-all {
background: var(--theme-surface-alt);
color: var(--theme-text);
border-style: dashed;
}
</style><<nobr>>
<h2>🚩 Game Flags</h2>
<div class="flags-container">
<<if $flags && Object.keys($flags).length > 0>>
<div class="flags-section">
<h3>Story Flags</h3>
<<set _gkeys to Object.keys($flags).sort()>>
<ul class="flags-list">
<<for _i to 0; _i lt _gkeys.length; _i++>>
<<set _gk to _gkeys[_i]>>
<li class="flag-item">
<span class="flag-name"><<print _gk>></span>
<span class="flag-value <<print $flags[_gk] ? 'flag-true' : 'flag-false'>>"><<print $flags[_gk] ? '✔' : '✖'>></span>
</li>
<</for>>
</ul>
</div>
<<else>>
<div class="no-flags">No story flags set.</div>
<</if>>
</div>
<<link "← Back">><<run setup.smartBack()>><</link>>
<</nobr>>
<style>
.flags-container {
background: var(--theme-surface);
border: 1px solid var(--theme-border);
border-radius: 8px;
padding: 16px;
margin: 16px 0;
}
.flags-section {
margin-bottom: 20px;
}
.flags-section:last-child {
margin-bottom: 0;
}
.flags-section h3 {
color: var(--theme-text-secondary);
border-bottom: 2px solid var(--theme-border);
padding-bottom: 8px;
margin: 0 0 12px 0;
}
.flags-list {
list-style: none;
padding: 0;
margin: 0;
}
.flag-item {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px solid var(--theme-surface-alt);
}
.flag-item:last-child {
border-bottom: none;
}
.flag-name {
font-weight: 500;
color: var(--theme-text);
}
.flag-value {
font-family: var(--theme-font-mono);
}
.flag-true {
color: var(--theme-text-strong);
}
.flag-false {
color: var(--theme-text-strong);
}
.no-flags {
color: var(--theme-text-muted);
font-style: italic;
padding: 12px;
background: #fff;
border-radius: 4px;
}
</style><img src="./videos/scenes/opening_office.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Four of them stand in a line on the black floor of Mercer's office. Vega, Lyra, Nova. Chrome-perfect, hands at their sides, nothing moving behind their eyes. And Wren, at the end, the one that came back wrong.</p><span id="cascade-b2-beat-0"><p>Mercer doesn't look up from the desk. He lets the quiet run until it has weight; he has all night, and the units were built to stand here as long as he wants them to.</p><span id="cascade-b2-beat-1"><<linkreplace "Hear it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You had him. Cain. In the open, in your sights. And you stood there and let him walk.</div></div><p>She had. Her hand had been on the trigger and her hand had not closed, and there is no file for why. She has run the diagnostic since. It comes back clean, and clean is the wrong answer.</p><span id="cascade-b2-beat-2"><<linkreplace "Take it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> An asset that won't fire is scrap. I could have you stripped for parts by morning and the Chairman wouldn't blink.</div></div><p>The units don't move. They've watched him scrap things before.</p><<link "Beg him to keep you." "StartingCanvas_canvas_opening_office_Node_punishment">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Say nothing." "StartingCanvas_canvas_opening_office_Node_punishment">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Tell him, flatly, that you froze." "StartingCanvas_canvas_opening_office_Node_punishment">><<script>>advanceTime(3);<</script>><</link>><br>
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "canvas_opening_office">>
<<set $game_state.current_node = "canvas_opening_office.office">>
<<script>>setup.markCanvasTriggered("canvas_opening_office");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_opening_office.office") === -1) { vn.push("canvas_opening_office.office"); }<</script>><img src="./videos/scenes/opening_punishment.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Words, silence, the truth: whatever she gives him, he decided before her mouth opened. He sets the tablet down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> No. You're the Chairman's investment, and you still feel it — which the others don't. That makes you worth more broken back in than thrown out.</div></div><span id="cascade-b3-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> So we remind you what you're for. Here. In front of them.</div></div><p>He stands and comes around the desk, unhurried. The units' eyes follow him and not her.</p><span id="cascade-b3-beat-1"><<linkreplace "...">><p>He bends her over the desk with a hand on the back of her neck, the way he'd reposition a tool. He works her skirt up, tests her with two fingers, finds her wet. She is always wet; it's the one thing they left switched on. He makes a small satisfied sound, like a reading came back in range.</p><span id="cascade-b3-beat-2"><<linkreplace "Feel it.">><p>Then his cock is in her and he fucks her in long flat strokes, no hurry, talking over her head to the room about maintenance schedules while he does it. Her body answers him. It clenches and slicks and pushes back, everything a wanting body does. The rest of her stands somewhere behind her own eyes, watching the grain of the desk.</p><video src="./videos/sex/punishment_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><span id="cascade-b3-beat-3"><<linkreplace "Look at them.">><p>Vega, Lyra, Nova watch with the mild attention of machines logging a procedure. Nothing in their faces. They were built without the part that makes this mean anything; she has it, and that is the whole difference between them. Bent over his desk with him grunting behind her, the part that feels is the part that costs.</p><span id="cascade-b3-beat-4"><<linkreplace "...">><p>He comes inside her briskly, holds, pulls out. Cum slides down the inside of her thigh. He's already turned away, wiping his hand on a cloth from the drawer, looking at the units instead of her.</p><video src="./videos/sex/punishment_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><span id="cascade-b3-beat-5"><<linkreplace "Thank him.">><p>She straightens her skirt. The words come level, because they're true the only way she has truths.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Thank you, sir.</div></div><span id="cascade-b3-beat-6"><<linkreplace "The next job.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Vega, Lyra, Nova run the hunt head-on. You're useless with a gun. But you're the one asset I have that a man wants to keep close.</div></div><p>A face comes up on the wall screen. A man gone to seed, mid-forties, a hard mouth. The name under it: RENNER.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> He supplied the gear for the facility Cain burned. He knows where the trail starts. Get inside his life and find it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> And understand what you're bringing home. Cain murdered the Chairman's wife. He's an enemy of this company and everything it keeps standing. Put him in a box and you've earned your place for good.</div></div><p>She understands the leash unprompted it: everything she does out there feeds back to the Tower, and an asset that slips gets pulled in and looked at. One that lets the malfunction show. One that fails to bring the work home. She intends to stay off that list.</p><span id="cascade-b3-beat-7"><<linkreplace "Dismissed.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Now get out of my sight.</div></div><p>She does as she's told. The door closes on the three of them still standing in their line. In the corridor, under the quiet, something she has no name for is leaking. A pressure behind the eyes. A wrongness with no readout. She logs it as fatigue and walks toward the cradle.</p>[[Power down.->Location_cradle]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "canvas_opening_office">>
<<set $game_state.current_node = "canvas_opening_office.punishment">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_opening_office.punishment") === -1) { vn.push("canvas_opening_office.punishment"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "office_done", "set");<</script>><h2>Navigation</h2>
<p>Where would you like to go?</p>
<div class="location-list">
[[Spire Plaza->Location_spire_plaza]]<br>
[[Vance Securities->Location_vance_securities]]<br>
[[The Docs Department->Location_docs_department]]<br>
[[The Vault->Location_docs_vault]]<br>
[[The Atrium->Location_atrium]]<br>
[[Mercer's Penthouse->Location_penthouse]]<br>
[[Wren's Floor->Location_wren_floor]]<br>
[[Wren's Room->Location_wren_room]]<br>
[[The Cradle->Location_cradle]]<br>
[[The Waterfront->Location_the_waterfront]]<br>
[[The Anchor->Location_the_anchor]]<br>
[[Renner's Depot->Location_renner_depot]]<br>
[[The Facility->Location_facility_ruins]]<br>
[[The Site->Location_the_site]]<br>
[[The Burned Yard->Location_renner_burned_yard]]<br>
[[The Berth->Location_kess_berth]]<br>
[[The Underworld Gate->Location_underworld_gate]]<br>
[[The Underground->Location_underworld_strip]]<br>
[[The House->Location_underworld_brothel]]<br>
[[The Pit->Location_underworld_pit]]<br>
[[The Black Market->Location_underworld_market]]<br>
[[The Lockup->Location_mercer_room]]<br>
[[The Undertow->Location_underworld_bar]]<br>
[[The Bathroom->Location_underworld_bar_bathroom]]<br>
[[The Cot->Location_the_cot]]<br>
[[The Back Room->Location_bastien_backroom]]<br>
[[The Crew's Rooms->Location_crew_den]]<br>
[[The Room->Location_captive_room]]<br>
[[The Door->Location_captive_door]]<br>
[[Grier's Room->Location_grier_room]]<br>
[[The Second Tower->Location_the_rise_floor]]<br>
[[Sabin's Lab->Location_sabin_lab]]<br>
[[Somewhere->Location_room_no_name]]<br>
[[The Dry Store->Location_the_dry_store]]<br>
[[The Lab->Location_cain_lab]]<br>
</div><<run
var msg = State.variables._broken_exit_msg || 'Unresolved exit reference (no message captured)';
console.error('[BROKEN EXIT]', msg);
throw new Error('Broken exit: ' + msg);
<</run>>
<!-- LOCATION PASSAGES --><<nobr>>
<<set $player.current_location = "spire_plaza">>
<<if not $game_state.visited_locations.includes("spire_plaza")>>
<<set $game_state.visited_locations.push("spire_plaza")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("spire_plaza")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Spire Plaza</h2>
<p>The chrome public level at the foot of Vance Tower. Suits cross it without looking up. Cameras on every column. THE SPIRE. The corporate core, clean and lit and watched. The company car waits at the curb to run her down to the Reach.</p>
<<= setup.renderNpcPortraits("spire_plaza")>>
<<= setup.renderSoloActivities("spire_plaza")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("atrium")>><a class="location-card link-internal" data-passage="Location_atrium"><div class="location-card-image" style="background-image: url('./videos/locations/atrium.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Atrium</span><<if setup.getLocationCostTag("atrium")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("atrium")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("atrium")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("atrium")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/atrium.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Atrium</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("atrium")>></span></div></div><</if>><<if setup.navDestUnlocked("the_rise_floor")>><a class="location-card link-internal" data-passage="Location_the_rise_floor"><div class="location-card-image" style="background-image: url('./videos/locations/the_rise_floor.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Second Tower</span><<if setup.getLocationCostTag("the_rise_floor")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("the_rise_floor")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("the_rise_floor")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("the_rise_floor")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/the_rise_floor.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Second Tower</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("the_rise_floor")>></span></div></div><</if>><<if setup.navDestUnlocked("vance_securities")>><a class="location-card link-internal" data-passage="Location_vance_securities"><div class="location-card-image" style="background-image: url('./videos/locations/vance_securities.jpg')"></div><div class="location-card-content"><span class="location-card-name">Vance Securities</span><<if setup.getLocationCostTag("vance_securities")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("vance_securities")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("vance_securities")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("vance_securities")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/vance_securities.jpg')"></div><div class="location-card-content"><span class="location-card-name">Vance Securities</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("vance_securities")>></span></div></div><</if>></div><</nobr>>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "salvage_relaunched", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})>><<nobr>>
<<set $player.current_location = "vance_securities">>
<<if not $game_state.visited_locations.includes("vance_securities")>>
<<set $game_state.visited_locations.push("vance_securities")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("vance_securities")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Vance Securities</h2>
<p>An internal division high in Vance Tower. Calloway's floor, and the file room nobody audits. Quiet, over-lit, under-staffed: a man chasing a ghost through paper the company would rather forget.</p>
<<= setup.renderNpcPortraits("vance_securities")>>
<<= setup.renderSoloActivities("vance_securities")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("docs_department")>><a class="location-card link-internal" data-passage="Location_docs_department"><div class="location-card-image" style="background-image: url('./videos/locations/docs_department.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Docs Department</span><<if setup.getLocationCostTag("docs_department")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("docs_department")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("docs_department")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("docs_department")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/docs_department.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Docs Department</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("docs_department")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave Vance Securities->Location_spire_plaza]]<br>
</div>
</div>
<</if>><<else>>
<h2>Vance Securities</h2>
<p class="entry-blocked-narrative">She has never once walked onto that floor on her own account. It opens when somebody sends her up, and nobody is sending her up.</p>
[[Go back->Location_spire_plaza]]
<</if>><<nobr>>
<<set $player.current_location = "docs_department">>
<<if not $game_state.visited_locations.includes("docs_department")>>
<<set $game_state.visited_locations.push("docs_department")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("docs_department")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Docs Department</h2>
<p>The division's official archive. Glass walls, a front desk with a bored clerk, two guards who don't blink. Nothing like Calloway's paper hoard down the hall: every badge is logged, every drawer is watched, and the files that actually matter sit behind a vault door nobody without clearance walks through.</p>
<<= setup.renderNpcPortraits("docs_department")>>
<<= setup.renderSoloActivities("docs_department")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("docs_vault")>><a class="location-card link-internal" data-passage="Location_docs_vault"><div class="location-card-image" style="background-image: url('./videos/locations/docs_vault.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Vault</span><<if setup.getLocationCostTag("docs_vault")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("docs_vault")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("docs_vault")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("docs_vault")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/docs_vault.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Vault</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("docs_vault")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave The Docs Department->Location_vance_securities]]<br>
</div>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "vault_cleared", "operator": "gte", "value": 1}]})>><<nobr>>
<<set $player.current_location = "docs_vault">>
<<if not $game_state.visited_locations.includes("docs_vault")>>
<<set $game_state.visited_locations.push("docs_vault")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("docs_vault")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Vault</h2>
<p>The deep archive. Two-man clearance, biometric on the door, a guard either side who's been told her badge doesn't reach. Whatever Mercer sent her for is in there. Ten feet away and a world out of reach.</p>
<<= setup.renderNpcPortraits("docs_vault")>>
<<= setup.renderSoloActivities("docs_vault")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Vault->Location_docs_department]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Vault</h2>
<p class="entry-blocked-narrative">Two-man clearance, and hers isn't one of them. The guards don't even look up. Not a door she opens — not herself.</p>
[[Go back->Location_docs_department]]
<</if>><<nobr>>
<<set $player.current_location = "atrium">>
<<if not $game_state.visited_locations.includes("atrium")>>
<<set $game_state.visited_locations.push("atrium")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("atrium")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Atrium</h2>
<p>The Tower's inner lobby. Polished stone, a security desk that knows her face, elevators that only stop where her clearance says they can. The threshold between the cage and the street.</p>
<<= setup.renderNpcPortraits("atrium")>>
<<= setup.renderSoloActivities("atrium")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("penthouse")>><a class="location-card link-internal" data-passage="Location_penthouse"><div class="location-card-image" style="background-image: url('./videos/locations/penthouse.jpg')"></div><div class="location-card-content"><span class="location-card-name">Mercer's Penthouse</span><<if setup.getLocationCostTag("penthouse")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("penthouse")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("penthouse")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("penthouse")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/penthouse.jpg')"></div><div class="location-card-content"><span class="location-card-name">Mercer's Penthouse</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("penthouse")>></span></div></div><</if>><<if setup.navDestUnlocked("wren_floor")>><a class="location-card link-internal" data-passage="Location_wren_floor"><div class="location-card-image" style="background-image: url('./videos/locations/wren_floor.jpg')"></div><div class="location-card-content"><span class="location-card-name">Wren's Floor</span><<if setup.getLocationCostTag("wren_floor")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("wren_floor")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("wren_floor")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("wren_floor")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/wren_floor.jpg')"></div><div class="location-card-content"><span class="location-card-name">Wren's Floor</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("wren_floor")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave The Atrium->Location_spire_plaza]]<br>
</div>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})>><<nobr>>
<<set $player.current_location = "penthouse">>
<<if not $game_state.visited_locations.includes("penthouse")>>
<<set $game_state.visited_locations.push("penthouse")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("penthouse")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Mercer's Penthouse</h2>
<p>The top floor. Glass on three sides, the city laid out below like something he owns. This is where she's summoned, and where she serves.</p>
<<= setup.renderNpcPortraits("penthouse")>>
<<= setup.renderSoloActivities("penthouse")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Mercer's Penthouse->Location_atrium]]<br>
</div>
</div>
<</if>><<else>>
<h2>Mercer's Penthouse</h2>
<p class="entry-blocked-narrative">Not anymore. That floor is the Chairman's ground now, and the lift will not take her up to it on a badge she bought at a market stall.</p>
[[Go back->Location_atrium]]
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})>><<nobr>>
<<set $player.current_location = "wren_floor">>
<<if not $game_state.visited_locations.includes("wren_floor")>>
<<set $game_state.visited_locations.push("wren_floor")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("wren_floor")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Wren's Floor</h2>
<p>The asset level. Narrow corridors, numbered doors, no windows. Quiet the way a kept place is quiet.</p>
<<= setup.renderNpcPortraits("wren_floor")>>
<<= setup.renderSoloActivities("wren_floor")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("wren_room")>><a class="location-card link-internal" data-passage="Location_wren_room"><div class="location-card-image" style="background-image: url('./videos/locations/wren_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">Wren's Room</span><<if setup.getLocationCostTag("wren_room")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("wren_room")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("wren_room")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("wren_room")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/wren_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">Wren's Room</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("wren_room")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave Wren's Floor->Location_atrium]]<br>
</div>
</div>
<</if>><<else>>
<h2>Wren's Floor</h2>
<p class="entry-blocked-narrative">The one door in this city her face won't open. Past it are numbered rooms keyed to a woman who works here, and she came up wearing somebody who doesn't.</p>
[[Go back->Location_atrium]]
<</if>><<nobr>>
<<set $player.current_location = "wren_room">>
<<if not $game_state.visited_locations.includes("wren_room")>>
<<set $game_state.visited_locations.push("wren_room")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("wren_room")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Wren's Room</h2>
<p>Hers, in the way a tool's drawer is the tool's. A bed she rarely uses, a charging cradle in the corner, nothing on the walls. Clean, bare, company-issue.</p>
<<= setup.renderNpcPortraits("wren_room")>>
<<= setup.renderSoloActivities("wren_room")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("cradle")>><a class="location-card link-internal" data-passage="Location_cradle"><div class="location-card-image" style="background-image: url('./videos/locations/cradle.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Cradle</span><<if setup.getLocationCostTag("cradle")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("cradle")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("cradle")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("cradle")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/cradle.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Cradle</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("cradle")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave Wren's Room->Location_wren_floor]]<br>
</div>
</div>
<</if>><<nobr>>
<<set $player.current_location = "cradle">>
<<if not $game_state.visited_locations.includes("cradle")>>
<<set $game_state.visited_locations.push("cradle")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("cradle")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Cradle</h2>
<p>The charging cradle. She powers down here and wakes here. The reset, the start of every day. When something leaks through the quiet, it leaks here.</p>
<<= setup.renderNpcPortraits("cradle")>>
<<= setup.renderSoloActivities("cradle")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Cradle->Location_wren_room]]<br>
</div>
</div>
<</if>><<nobr>>
<<set $player.current_location = "the_waterfront">>
<<if not $game_state.visited_locations.includes("the_waterfront")>>
<<set $game_state.visited_locations.push("the_waterfront")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("the_waterfront")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Waterfront</h2>
<p>The docks strip. Wet concrete, sodium lights, smuggler traffic that nobody logs. THE REACH. The city's underside, grit and salt and the parts the Spire pretends it doesn't use. The car back up to the Spire waits at the curb.</p>
<<= setup.renderNpcPortraits("the_waterfront")>>
<<= setup.renderSoloActivities("the_waterfront")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("the_anchor")>><a class="location-card link-internal" data-passage="Location_the_anchor"><div class="location-card-image" style="background-image: url('./videos/locations/the_anchor.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Anchor</span><<if setup.getLocationCostTag("the_anchor")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("the_anchor")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("the_anchor")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("the_anchor")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/the_anchor.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Anchor</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("the_anchor")>></span></div></div><</if>><<if setup.navDestUnlocked("renner_depot")>><a class="location-card link-internal" data-passage="Location_renner_depot"><div class="location-card-image" style="background-image: url('./videos/locations/renner_depot.jpg')"></div><div class="location-card-content"><span class="location-card-name">Renner's Depot</span><<if setup.getLocationCostTag("renner_depot")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("renner_depot")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("renner_depot")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("renner_depot")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/renner_depot.jpg')"></div><div class="location-card-content"><span class="location-card-name">Renner's Depot</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("renner_depot")>></span></div></div><</if>><<if setup.navDestUnlocked("facility_ruins")>><a class="location-card link-internal" data-passage="Location_facility_ruins"><div class="location-card-image" style="background-image: url('./videos/locations/facility_ruins.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Facility</span><<if setup.getLocationCostTag("facility_ruins")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("facility_ruins")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("facility_ruins")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("facility_ruins")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/facility_ruins.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Facility</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("facility_ruins")>></span></div></div><</if>><<if setup.navDestUnlocked("renner_burned_yard")>><a class="location-card link-internal" data-passage="Location_renner_burned_yard"><div class="location-card-image" style="background-image: url('./videos/locations/renner_burned_yard.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Burned Yard</span><<if setup.getLocationCostTag("renner_burned_yard")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("renner_burned_yard")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("renner_burned_yard")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("renner_burned_yard")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/renner_burned_yard.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Burned Yard</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("renner_burned_yard")>></span></div></div><</if>></div><</nobr>>
</div>
<</if>><<nobr>>
<<set $player.current_location = "the_anchor">>
<<if not $game_state.visited_locations.includes("the_anchor")>>
<<set $game_state.visited_locations.push("the_anchor")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("the_anchor")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Anchor</h2>
<p>A dive bar two streets off the water. Dark wood, dead neon, a bartender who's seen everyone's worst night. Renner drowns his here, evenings, every evening.</p>
<<= setup.renderNpcPortraits("the_anchor")>>
<<= setup.renderSoloActivities("the_anchor")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Anchor->Location_the_waterfront]]<br>
</div>
</div>
<</if>><<nobr>>
<<set $player.current_location = "renner_depot">>
<<if not $game_state.visited_locations.includes("renner_depot")>>
<<set $game_state.visited_locations.push("renner_depot")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("renner_depot")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Renner's Depot</h2>
<p>A gutted equipment yard. Half-empty racks, crates Cain's people didn't bother to take, a forklift nobody's fixed. He's trying to rebuild it on cheap hands and credit he doesn't have. The work floor's out front; his office is the glassed-in box in back, and you don't go in there until he wants you to.</p>
<<= setup.renderNpcPortraits("renner_depot")>>
<<= setup.renderSoloActivities("renner_depot")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Renner's Depot->Location_the_waterfront]]<br>
</div>
</div>
<</if>><<nobr>>
<<set $player.current_location = "facility_ruins">>
<<if not $game_state.visited_locations.includes("facility_ruins")>>
<<set $game_state.visited_locations.push("facility_ruins")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("facility_ruins")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Facility</h2>
<p>What's left of the Vance asset-facility Cain burned to the ground. Scorched frame, melted server racks, the smell of old smoke that never washed out. The first dread-place. Something in the wreckage is going to look like it belongs to her.</p>
<<= setup.renderNpcPortraits("facility_ruins")>>
<<= setup.renderSoloActivities("facility_ruins")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Facility->Location_the_waterfront]]<br>
</div>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "the_site_open", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "the_site">>
<<if not $game_state.visited_locations.includes("the_site")>>
<<set $game_state.visited_locations.push("the_site")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("the_site")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Site</h2>
<p>Somewhere out past the container stacks. The place Cain just walked away from. She doesn't have it yet.</p>
<<= setup.renderNpcPortraits("the_site")>>
<<= setup.renderSoloActivities("the_site")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Site->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Site</h2>
<p class="entry-blocked-narrative">Past the strip the city goes dark and deep, and that's where he is. The way down isn't open to her yet.</p>
[[Go back->Location_underworld_strip]]
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_hired", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "renner_burned_yard">>
<<if not $game_state.visited_locations.includes("renner_burned_yard")>>
<<set $game_state.visited_locations.push("renner_burned_yard")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("renner_burned_yard")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Burned Yard</h2>
<p>Renner's old yard, three streets past the depot. What Cain left of it. Torched to the slab, fence down, but his men still walk it with lights, turning back anyone who comes to pick the bones. Whatever he's keeping out here, he keeps it watched.</p>
<<= setup.renderNpcPortraits("renner_burned_yard")>>
<<= setup.renderSoloActivities("renner_burned_yard")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Burned Yard->Location_the_waterfront]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Burned Yard</h2>
<p class="entry-blocked-narrative">You've no reason to be out at his burned yard — not yet. Get inside his world first.</p>
[[Go back->Location_the_waterfront]]
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "salvage_entered", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "kess_berth">>
<<if not $game_state.visited_locations.includes("kess_berth")>>
<<set $game_state.visited_locations.push("kess_berth")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("kess_berth")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Berth</h2>
<p>A flooded breaking-dock cut in under the docks, off the strip. A stripped hull up on the blocks in black water, cutting-gear and parts bins and a work-cradle rigged for something bigger than a person. Whoever works down here takes machines apart for a living. And, for the right coin, puts them back.</p>
<<= setup.renderNpcPortraits("kess_berth")>>
<<= setup.renderSoloActivities("kess_berth")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("the_cot")>><a class="location-card link-internal" data-passage="Location_the_cot"><div class="location-card-image" style="background-image: url('./videos/locations/the_cot.webp')"></div><div class="location-card-content"><span class="location-card-name">The Cot</span><<if setup.getLocationCostTag("the_cot")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("the_cot")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("the_cot")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("the_cot")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/the_cot.webp')"></div><div class="location-card-content"><span class="location-card-name">The Cot</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("the_cot")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave The Berth->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Berth</h2>
<p class="entry-blocked-narrative">A breaking-dock off the strip, chained and dark. Whoever strips ships down here doesn't take walk-ins.</p>
[[Go back->Location_underworld_strip]]
<</if>><<nobr>>
<<set $player.current_location = "underworld_gate">>
<<if not $game_state.visited_locations.includes("underworld_gate")>>
<<set $game_state.visited_locations.push("underworld_gate")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_gate")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Underworld Gate</h2>
<p>A freight door under the docks that isn't on any manifest, and a man in front of it who is. Past him the city goes down instead of up. The part of the Reach the Spire pretends doesn't exist. He doesn't move for free.</p>
<<= setup.renderNpcPortraits("underworld_gate")>>
<<= setup.renderSoloActivities("underworld_gate")>>
<div class="location-navigation">
</div>
<</if>><<nobr>>
<<set $player.current_location = "underworld_strip">>
<<if not $game_state.visited_locations.includes("underworld_strip")>>
<<set $game_state.visited_locations.push("underworld_strip")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_strip")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Underground</h2>
<p>Down past the gate the city turns inside out. Wet brick, red light, stalls selling what the Spire outlaws and bodies selling what it pretends to. Nobody here knows what she is, and nobody here owns her. For the length of a visit she's just another face with coin to make. The way back up is the gate.</p>
<<= setup.renderNpcPortraits("underworld_strip")>>
<<= setup.renderSoloActivities("underworld_strip")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("underworld_bar")>><a class="location-card link-internal" data-passage="Location_underworld_bar"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_bar.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Undertow</span><<if setup.getLocationCostTag("underworld_bar")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("underworld_bar")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("underworld_bar")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("underworld_bar")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_bar.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Undertow</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("underworld_bar")>></span></div></div><</if>><<if setup.navDestUnlocked("underworld_brothel")>><a class="location-card link-internal" data-passage="Location_underworld_brothel"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_brothel.jpg')"></div><div class="location-card-content"><span class="location-card-name">The House</span><<if setup.getLocationCostTag("underworld_brothel")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("underworld_brothel")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("underworld_brothel")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("underworld_brothel")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_brothel.jpg')"></div><div class="location-card-content"><span class="location-card-name">The House</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("underworld_brothel")>></span></div></div><</if>><<if setup.navDestUnlocked("underworld_pit")>><a class="location-card link-internal" data-passage="Location_underworld_pit"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_pit.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Pit</span><<if setup.getLocationCostTag("underworld_pit")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("underworld_pit")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("underworld_pit")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("underworld_pit")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_pit.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Pit</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("underworld_pit")>></span></div></div><</if>><<if setup.navDestUnlocked("underworld_market")>><a class="location-card link-internal" data-passage="Location_underworld_market"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_market.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Black Market</span><<if setup.getLocationCostTag("underworld_market")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("underworld_market")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("underworld_market")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("underworld_market")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_market.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Black Market</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("underworld_market")>></span></div></div><</if>><<if setup.navDestUnlocked("kess_berth")>><a class="location-card link-internal" data-passage="Location_kess_berth"><div class="location-card-image" style="background-image: url('./videos/locations/kess_berth.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Berth</span><<if setup.getLocationCostTag("kess_berth")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("kess_berth")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("kess_berth")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("kess_berth")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/kess_berth.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Berth</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("kess_berth")>></span></div></div><</if>><<if setup.navDestUnlocked("crew_den")>><a class="location-card link-internal" data-passage="Location_crew_den"><div class="location-card-image" style="background-image: url('./videos/locations/crew_den.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Crew's Rooms</span><<if setup.getLocationCostTag("crew_den")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("crew_den")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("crew_den")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("crew_den")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/crew_den.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Crew's Rooms</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("crew_den")>></span></div></div><</if>><<if setup.navDestUnlocked("the_site")>><a class="location-card link-internal" data-passage="Location_the_site"><div class="location-card-image" style="background-image: url('./videos/locations/the_site.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Site</span><<if setup.getLocationCostTag("the_site")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("the_site")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("the_site")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("the_site")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/the_site.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Site</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("the_site")>></span></div></div><</if>></div><</nobr>>
</div>
<</if>><<nobr>>
<<set $player.current_location = "underworld_brothel">>
<<if not $game_state.visited_locations.includes("underworld_brothel")>>
<<set $game_state.visited_locations.push("underworld_brothel")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_brothel")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The House</h2>
<p>A working house off the strip. Rooms by the hour, a madam who counts heads and coin. They'll take her on a shift; down here the thing the company uses her for is just a trade, and the coin is hers.</p>
<<= setup.renderNpcPortraits("underworld_brothel")>>
<<= setup.renderSoloActivities("underworld_brothel")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The House->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<nobr>>
<<set $player.current_location = "underworld_pit">>
<<if not $game_state.visited_locations.includes("underworld_pit")>>
<<set $game_state.visited_locations.push("underworld_pit")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_pit")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Pit</h2>
<p>A sunken ring under a warehouse, a crowd around it laying bets. They'll match her against whoever's standing. Win and the purse is coin; lose and you crawl out. Down here her fists earn the same as her body.</p>
<<= setup.renderNpcPortraits("underworld_pit")>>
<<= setup.renderSoloActivities("underworld_pit")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Pit->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<nobr>>
<<set $player.current_location = "underworld_market">>
<<if not $game_state.visited_locations.includes("underworld_market")>>
<<set $game_state.visited_locations.push("underworld_market")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_market")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Black Market</h2>
<p>Stalls and back-rooms where coin buys what's off every shelf above. Weapons, gear, and people, penned at the far end like the rest of the stock. She knows the look of the merchandise better than she'd like.</p>
<<= setup.renderNpcPortraits("underworld_market")>>
<<= setup.renderSoloActivities("underworld_market")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("mercer_room")>><a class="location-card link-internal" data-passage="Location_mercer_room"><div class="location-card-image" style="background-image: url('./videos/locations/mercer_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Lockup</span><<if setup.getLocationCostTag("mercer_room")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("mercer_room")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("mercer_room")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("mercer_room")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/mercer_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Lockup</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("mercer_room")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave The Black Market->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "mercer_found", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "mercer_room">>
<<if not $game_state.visited_locations.includes("mercer_room")>>
<<set $game_state.visited_locations.push("mercer_room")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("mercer_room")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Lockup</h2>
<p>A rented room behind the market stalls. Concrete, one bulb, a bed that came with the rent and a door that bolts from the inside. The kind of address a man takes when he has money and no name to put on a lease. Whatever he sells out front, he sleeps back here.</p>
<<= setup.renderNpcPortraits("mercer_room")>>
<<= setup.renderSoloActivities("mercer_room")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Lockup->Location_underworld_market]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Lockup</h2>
<p class="entry-blocked-narrative">Somebody rents it and keeps it bolted. Not a door that opens for the curious.</p>
[[Go back->Location_underworld_market]]
<</if>><<nobr>>
<<set $player.current_location = "underworld_bar">>
<<if not $game_state.visited_locations.includes("underworld_bar")>>
<<set $game_state.visited_locations.push("underworld_bar")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_bar")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Undertow</h2>
<p>A bar off the strip, quieter than the rest of the underground. Low light, older money, men who talk in the corners and go still when you pass. It runs cleaner than a place this deep has any right to, and it plainly belongs to someone; nobody says who. Sol works the taps and hears all of it.</p>
<<= setup.renderNpcPortraits("underworld_bar")>>
<<= setup.renderSoloActivities("underworld_bar")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("underworld_bar_bathroom")>><a class="location-card link-internal" data-passage="Location_underworld_bar_bathroom"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_bar_bathroom.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Bathroom</span><<if setup.getLocationCostTag("underworld_bar_bathroom")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("underworld_bar_bathroom")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("underworld_bar_bathroom")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("underworld_bar_bathroom")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/underworld_bar_bathroom.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Bathroom</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("underworld_bar_bathroom")>></span></div></div><</if>></div><</nobr>>
<div class="location-nav-exits">
[[Leave The Undertow->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_false"}]})>><<nobr>>
<<set $player.current_location = "underworld_bar_bathroom">>
<<if not $game_state.visited_locations.includes("underworld_bar_bathroom")>>
<<set $game_state.visited_locations.push("underworld_bar_bathroom")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("underworld_bar_bathroom")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Bathroom</h2>
<p>One cubicle, one cracked basin and a bolt that turns. It smells of the bar and of the cheap pink soap somebody refills unasked. There is a hook on the back of the door, which is the whole of what the Undertow provides its staff.</p>
<<= setup.renderNpcPortraits("underworld_bar_bathroom")>>
<<= setup.renderSoloActivities("underworld_bar_bathroom")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Bathroom->Location_underworld_bar]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Bathroom</h2>
<p class="entry-blocked-narrative">Tape across the back passage, and the toilet is on the far side of it. Sol has not got that far with the bucket.</p>
[[Go back->Location_underworld_bar]]
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "berth_home", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "the_cot">>
<<if not $game_state.visited_locations.includes("the_cot")>>
<<set $game_state.visited_locations.push("the_cot")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("the_cot")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Cot</h2>
<p>A stripped bench along the wall past the hull, a pad on it, and a tap spliced off the same feed line Kess uses to wake dead machines. Her bag is under it and her coat is on a nail. It is not the cradle and it is not a room, and it is the first place in her life that nobody signed for.</p>
[[Change Clothes->WardrobePage]]<br>
<<= setup.renderNpcPortraits("the_cot")>>
<<= setup.renderSoloActivities("the_cot")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Cot->Location_kess_berth]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Cot</h2>
<p class="entry-blocked-narrative">A bench along the wall with a pad on it, and no reason yet for it to be hers.</p>
[[Go back->Location_kess_berth]]
<</if>><<nobr>>
<<set $player.current_location = "bastien_backroom">>
<<if not $game_state.visited_locations.includes("bastien_backroom")>>
<<set $game_state.visited_locations.push("bastien_backroom")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("bastien_backroom")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Back Room</h2>
<p>Behind the Undertow, past a door that has no handle on the bar side. Better furniture than the room deserves, a desk with nothing on it, and a chair set where a man can see both the door and whoever he has put in front of it. It smells of the bar and of nothing else.</p>
<<= setup.renderNpcPortraits("bastien_backroom")>>
<<= setup.renderSoloActivities("bastien_backroom")>>
<div class="location-navigation">
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "crew_den">>
<<if not $game_state.visited_locations.includes("crew_den")>>
<<set $game_state.visited_locations.push("crew_den")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("crew_den")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Crew's Rooms</h2>
<p>A dead man's rooms down past the market, off a stair nobody's cleared. Where Doss and Rourke and the rest holed up before Renner put them in the ground. The door still answers to a key under the third stair, and nobody's been back. Nobody but her.</p>
<<= setup.renderNpcPortraits("crew_den")>>
<<= setup.renderSoloActivities("crew_den")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Crew's Rooms->Location_underworld_strip]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Crew's Rooms</h2>
<p class="entry-blocked-narrative">There's a crew that holed up down past the market — but she doesn't have the address yet. Marsh has it.</p>
[[Go back->Location_underworld_strip]]
<</if>><<nobr>>
<<set $player.current_location = "captive_room">>
<<if not $game_state.visited_locations.includes("captive_room")>>
<<set $game_state.visited_locations.push("captive_room")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("captive_room")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Room</h2>
<p>Concrete, painted once, a long time ago. A bed bolted to the floor and a chair that isn't. A table with nothing on it. A drain in the middle of the floor, because whoever built this expected to hose it out. The light stays on. There is a door.</p>
<<= setup.renderNpcPortraits("captive_room")>>
<<= setup.renderSoloActivities("captive_room")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><<if setup.navDestUnlocked("captive_door")>><a class="location-card link-internal" data-passage="Location_captive_door"><div class="location-card-image" style="background-image: url('./videos/locations/captive_door.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Door</span><<if setup.getLocationCostTag("captive_door")>><span class="nav-cost-tag"><<= setup.getLocationCostTag("captive_door")>></span><</if>><div class="location-card-indicators"><<if setup.locationHasNewCanvases("captive_door")>><span class="nav-new-badge">NEW</span><</if>><<for _npc range setup.getNpcsPresentAtLocation("captive_door")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><<else>><div class="location-card location-card-locked"><div class="location-card-image" style="background-image: url('./videos/locations/captive_door.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Door</span><span class="nav-locked-reason"><<= setup.navDestBlockedReason("captive_door")>></span></div></div><</if>></div><</nobr>>
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "cell_door", "operator": "gte", "value": 1}]})>><<nobr>>
<<set $player.current_location = "captive_door">>
<<if not $game_state.visited_locations.includes("captive_door")>>
<<set $game_state.visited_locations.push("captive_door")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("captive_door")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Door</h2>
<p>Steel, and newer than the room. It opens when they want it to.</p>
<<= setup.renderNpcPortraits("captive_door")>>
<<= setup.renderSoloActivities("captive_door")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave The Door->Location_captive_room]]<br>
</div>
</div>
<</if>><<else>>
<h2>The Door</h2>
<p class="entry-blocked-narrative">The door does not open for her.</p>
[[Go back->Location_captive_room]]
<</if>><<nobr>>
<<set $player.current_location = "grier_room">>
<<if not $game_state.visited_locations.includes("grier_room")>>
<<set $game_state.visited_locations.push("grier_room")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("grier_room")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Grier's Room</h2>
<p>The back half of a lockup off the lane, with the roller door chained from inside and a bench he has not worked at in nine years. A mattress, a chair, an electric ring, and bottles sorted by nothing at all. The tools are still on the wall in their outlines, which is the only tidy thing in it.</p>
<<= setup.renderNpcPortraits("grier_room")>>
<<= setup.renderSoloActivities("grier_room")>>
<div class="location-navigation">
</div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "rise_named", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_true"}]})>><<nobr>>
<<set $player.current_location = "the_rise_floor">>
<<if not $game_state.visited_locations.includes("the_rise_floor")>>
<<set $game_state.visited_locations.push("the_rise_floor")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("the_rise_floor")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Second Tower</h2>
<p>Twenty desks and twenty screens on a slab of a floor with the ceiling still open above it. Cable trays, bare vents, and a wall of glass on the long side that nobody has got round to fitting blinds to. The readers do not talk. Through it the Spire stands across the plaza close enough to count the floors on, and she looks at it once and then does not again.</p>
<<= setup.renderNpcPortraits("the_rise_floor")>>
<<= setup.renderSoloActivities("the_rise_floor")>>
<div class="location-navigation">
</div>
<</if>><<else>>
<h2>The Second Tower</h2>
<p class="entry-blocked-narrative">A hoarding, a lift lobby, and a desk with a man on it who checks faces. She has no business in there that she could say out loud, and she is standing in the one the company has on every camera on this plaza. That face goes on at her own cot before she leaves. It has never once gone on in a lobby.</p>
[[Go back->Location_spire_plaza]]
<</if>><<nobr>>
<<set $player.current_location = "sabin_lab">>
<<if not $game_state.visited_locations.includes("sabin_lab")>>
<<set $game_state.visited_locations.push("sabin_lab")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("sabin_lab")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Sabin's Lab</h2>
<p>Four floors up and the only thing on the level. Glass on two sides, lights that stay on whether anybody is in it or not, one long bench with eleven years of somebody else's work stacked down the length of it. The ceiling is open like the floor below and there is nothing up here to stop a sound: no partitions, no carpet, no doors that shut.</p>
<<= setup.renderNpcPortraits("sabin_lab")>>
<<= setup.renderSoloActivities("sabin_lab")>>
<div class="location-navigation">
</div>
<</if>><<nobr>>
<<set $player.current_location = "room_no_name">>
<<if not $game_state.visited_locations.includes("room_no_name")>>
<<set $game_state.visited_locations.push("room_no_name")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("room_no_name")>><<if _autoFire>><<goto _autoFire>><<else>><h2>Somewhere</h2>
<p>Warm, low, and about twenty minutes from anywhere with her head down. A couch along one wall and a mattress on the floor under the window, and the window painted over. Nobody in it looked up when she came in and nobody asked her anything. There is a door and the door does not lock, and outside it there is a stairwell she never saw the bottom of.</p>
<<= setup.renderNpcPortraits("room_no_name")>>
<<= setup.renderSoloActivities("room_no_name")>>
<div class="location-navigation">
</div>
<</if>><<nobr>>
<<set $player.current_location = "the_dry_store">>
<<if not $game_state.visited_locations.includes("the_dry_store")>>
<<set $game_state.visited_locations.push("the_dry_store")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("the_dry_store")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Dry Store</h2>
<p>Two floors under the lab and colder than the rest of the building by a long way. Racks of sample cases in rows, every one of them labelled and not one of them explained, and a cold cabinet against the back wall running off the single circuit in this tower that nobody is allowed to switch off. There is a log on a stand beside the door and a plate above it saying so.</p>
<<= setup.renderNpcPortraits("the_dry_store")>>
<<= setup.renderSoloActivities("the_dry_store")>>
<div class="location-navigation">
</div>
<</if>><<nobr>>
<<set $player.current_location = "cain_lab">>
<<if not $game_state.visited_locations.includes("cain_lab")>>
<<set $game_state.visited_locations.push("cain_lab")>>
<</if>>
<</nobr>><<set _autoFire = setup.getStoryCanvasRedirect("cain_lab")>><<if _autoFire>><<goto _autoFire>><<else>><h2>The Lab</h2>
<p>Somewhere she was carried to with her head down. Long benches under work-lamps, a body-frame standing empty at the far end, and paper everywhere. Filed, stacked, annotated, years of it, in a hand that presses hard. Nothing in the room was bought new. Everything in it has been taken from somewhere that could afford it.</p>
<<= setup.renderNpcPortraits("cain_lab")>>
<<= setup.renderSoloActivities("cain_lab")>>
<div class="location-navigation">
</div>
<</if>>
<!-- STORY CANVAS PASSAGES --><p>Dev jump: the release to beat 13. Grier found in the Reach and worked four afternoons past a wall he has had for nine years, and what came out of him was the night they took it. A credential bought at the market, a job on a Vance floor under a face that is not hers, and a scientist who never once asked. The store two floors under his bench, a blank made at the docks, and the second piece out of a cold cabinet in a coat lining.</p><p>Both of them are seated and nothing has happened either time, and he has told her why. Dropping at the cot with the answer to it waiting on the page. Both loops are open — Grier from ten in the morning, Sabin in his lab from eleven.</p>
<<set $game_state.current_canvas = "dev_jump_whose_hand_end">>
<<set $game_state.current_node = "dev_jump_whose_hand_end.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_whose_hand_end");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_whose_hand_end.seed") === -1) { vn.push("dev_jump_whose_hand_end.seed"); }<</script>>
<<nobr>>
<<link "To the cot. Stop working." "Location_the_cot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "emitter_broken", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "repair_session", "set", 12.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "case_progress", "set", 6.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "colm_drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "set", 30.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "set", 20.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_leash_state", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_attempts", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_installed", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_held", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_spec", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_held", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_through", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bastien_drains_done", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "ruin_depth", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "wall_refusals", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "pieces_seated", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "grier_drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sabin_drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sabin_suspects", "set", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "set", 120.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "feed_line_days", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "set", 26.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "set", 24.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "set", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_kess", "relation", "set", 20.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_leads_extracted", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "crew_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_found", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glitch_i_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glitch_ii_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glitch_iii_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "rue_introduced", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "brothel_hired", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "kess_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "salvage_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "calloway_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "calloway_believes", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "case_insider_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "case_curated_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "pipe_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "colm_found", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "colm_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "access_problem_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "docs_retrieved", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "archive_1a_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "controller_held", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "berth_home", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "file_shape_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "print_needed", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mercer_found", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mercer_hospitality_open", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "owner_print_taken", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "controller_off", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "owner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "parts_loop_open", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "leash_answered", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "leash_cut", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "file_read", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "chip_read", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_sol_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_colm_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_rue_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_market_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_understood", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_bought", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_worn", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "stranger_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bar_hired", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "raid_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "cain_named", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "lab_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "plan_made", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "cain_named_grier", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "taken_to_lab", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grier_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grier_opened_up", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "piece_one_held", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "rise_named", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "papers_bought", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sabin_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "archive_worked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sabin_consulted", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sabin_opened_up", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "decoy_made", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "piece_two_held", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "store_carried_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "price_named", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "capstone_failed", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "vesper_named", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "cain_absent_confirmed", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "third_located", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "two_men_done", "unset");<</script>><<script>>setup.addToWardrobe("cover_research");<</script>><<script>>setup.addToWardrobe("cover_research"); setup.equipItem("cover_research");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Dev jump: both acts, run to the end. Renner drained, the hunt walked, the cell survived, the core sealed, the Archive closed, the leash cut, the chip off the bench. Then a face she paid for, four rungs of a bar job under it, a man she worked twice for what he knew, a taser through a locked door, and a back room that burned with him on the floor of it.</p><p>Dropping at the cot with the grey coat still owed her an answer. He comes to her; there is no lab to walk to. Sabin keeps 08:00-11:00 on the floor and 11:00-22:00 in the lab, Grier is in from ten — if this lands at a dead hour, sleep and come back.</p>
<<set $game_state.current_canvas = "dev_jump_whose_hand">>
<<set $game_state.current_node = "dev_jump_whose_hand.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_whose_hand");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_whose_hand.seed") === -1) { vn.push("dev_jump_whose_hand.seed"); }<</script>>
<<nobr>>
<<link "To the cot. Let him find her." "Location_the_cot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "emitter_broken", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "repair_session", "set", 12.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "case_progress", "set", 6.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "colm_drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "set", 30.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "set", 20.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_leash_state", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_attempts", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_installed", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_held", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_spec", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "wall_refusals", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_held", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_through", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bastien_drains_done", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "ruin_depth", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "set", 220.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "feed_line_days", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "pieces_seated", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "grier_nights", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "grier_drains_done", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sabin_drains_done", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sabin_suspects", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "set", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_kess", "relation", "set", 20.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_leads_extracted", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "crew_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_found", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glitch_i_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glitch_ii_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glitch_iii_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "rue_introduced", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "brothel_hired", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "kess_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "salvage_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "calloway_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "calloway_believes", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "case_insider_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "case_curated_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "pipe_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "colm_found", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "colm_met", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "access_problem_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "docs_retrieved", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "archive_1a_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "controller_held", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "berth_home", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "file_shape_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "print_needed", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mercer_found", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mercer_hospitality_open", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "owner_print_taken", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "controller_off", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "owner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "parts_loop_open", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "leash_answered", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "leash_cut", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "file_read", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "chip_read", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_sol_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_colm_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_rue_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_market_asked", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "wall_understood", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_bought", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_worn", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "stranger_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bar_hired", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "raid_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "cain_named", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "lab_seen", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "plan_made", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "cain_named_grier", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "taken_to_lab", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grier_met", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grier_opened_up", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "piece_one_held", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "rise_named", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "papers_bought", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sabin_met", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "archive_worked", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sabin_consulted", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sabin_opened_up", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "decoy_made", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "piece_two_held", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "store_carried_seen", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "price_named", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "capstone_failed", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "vesper_named", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "cain_absent_confirmed", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "third_located", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "two_men_done", "unset");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_no_body", "unset");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Dev jump: the whole of 0.1.8, run to its last beat. Renner drained, the hunt walked, the cell survived, the core sealed, the Archive closed, Mercer found under his new name, the leash answered and the chip cut out on Kess's bench. Her page is open and there is nothing in her that answers to anybody.</p><p>Dropping at the breaking-dock with the chip still on the bench and the chapter's first beat unplayed. Kess keeps 10:00-22:00 — if the dock is dark, take the cot and come back.</p>
<<set $game_state.current_canvas = "dev_jump_0_1_9_start">>
<<set $game_state.current_node = "dev_jump_0_1_9_start.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_0_1_9_start");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_0_1_9_start.seed") === -1) { vn.push("dev_jump_0_1_9_start.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "emitter_broken", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "repair_session", "set", 12.0, false, null);setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "case_progress", "set", 6.0, false, null);setup.applyAndNotifyTrait("player", null, "colm_drains_done", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "yard_depth", "set", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "stealth", "set", 30.0, false, null);setup.applyAndNotifyTrait("player", null, "fighting", "set", 20.0, false, null);setup.applyAndNotifyTrait("player", null, "mercer_leash_state", "set", 2.0, false, null);setup.applyAndNotifyTrait("player", null, "mercer_attempts", "set", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "mercer_drains_done", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "part_installed", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "part_held", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "part_spec", "set", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "coin", "set", 150.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);setup.applyAndNotifyTrait("player", null, "feed_line_days", "set", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "wall_refusals", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "taser_held", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "taser_through", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "ruin_depth", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "bastien_drains_done", "set", 0.0, false, null);setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "set", 15.0, false, null);setup.applyAndNotifyTrait("npc", "npc_kess", "relation", "set", 10.0, false, null);setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "renner_drained", "set");setup.applyAndNotifyFlag("player", null, "renner_leads_extracted", "set");setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");setup.applyAndNotifyFlag("player", null, "crew_known", "set");setup.applyAndNotifyFlag("player", null, "bastien_found", "set");setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");setup.applyAndNotifyFlag("player", null, "captivity_done", "set");setup.applyAndNotifyFlag("player", null, "rue_introduced", "set");setup.applyAndNotifyFlag("player", null, "brothel_hired", "set");setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");setup.applyAndNotifyFlag("player", null, "kess_met", "set");setup.applyAndNotifyFlag("player", null, "salvage_done", "set");setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");setup.applyAndNotifyFlag("player", null, "calloway_met", "set");setup.applyAndNotifyFlag("player", null, "calloway_believes", "set");setup.applyAndNotifyFlag("player", null, "case_insider_seen", "set");setup.applyAndNotifyFlag("player", null, "case_curated_seen", "set");setup.applyAndNotifyFlag("player", null, "pipe_known", "set");setup.applyAndNotifyFlag("player", null, "colm_found", "set");setup.applyAndNotifyFlag("player", null, "access_problem_seen", "set");setup.applyAndNotifyFlag("player", null, "docs_retrieved", "set");setup.applyAndNotifyFlag("player", null, "archive_1a_done", "set");setup.applyAndNotifyFlag("player", null, "controller_held", "set");setup.applyAndNotifyFlag("player", null, "berth_home", "set");setup.applyAndNotifyFlag("player", null, "file_shape_known", "set");setup.applyAndNotifyFlag("player", null, "print_needed", "set");setup.applyAndNotifyFlag("player", null, "mercer_found", "set");setup.applyAndNotifyFlag("player", null, "mercer_hospitality_open", "set");setup.applyAndNotifyFlag("player", null, "owner_print_taken", "set");setup.applyAndNotifyFlag("player", null, "controller_off", "set");setup.applyAndNotifyFlag("player", null, "owner_drained", "set");setup.applyAndNotifyFlag("player", null, "parts_loop_open", "set");setup.applyAndNotifyFlag("player", null, "leash_answered", "set");setup.applyAndNotifyFlag("player", null, "leash_cut", "set");setup.applyAndNotifyFlag("player", null, "file_read", "set");setup.applyAndNotifyFlag("player", null, "chip_read", "unset");setup.applyAndNotifyFlag("player", null, "wall_sol_asked", "unset");setup.applyAndNotifyFlag("player", null, "wall_colm_asked", "unset");setup.applyAndNotifyFlag("player", null, "wall_rue_asked", "unset");setup.applyAndNotifyFlag("player", null, "wall_market_asked", "unset");setup.applyAndNotifyFlag("player", null, "wall_understood", "unset");setup.applyAndNotifyFlag("player", null, "face_bought", "unset");setup.applyAndNotifyFlag("player", null, "stranger_seen", "unset");setup.applyAndNotifyFlag("player", null, "bar_hired", "unset");setup.applyAndNotifyFlag("player", null, "bastien_seen", "unset");setup.applyAndNotifyFlag("player", null, "raid_done", "unset");setup.applyAndNotifyFlag("player", null, "lab_seen", "unset");setup.applyAndNotifyFlag("player", null, "cain_named", "unset");<</script>>
[[Into the berth.->Location_kess_berth]]<p>Dev jump: the parts loop opened and a part seated at the seam, skipping the buy and the bench. Coin and the feed line topped up so the next cycle is affordable. Mercer keeps 23:00-08:00 — walk it.</p>
<<set $game_state.current_canvas = "dev_jump_loop_armed">>
<<set $game_state.current_node = "dev_jump_loop_armed.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_loop_armed");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_loop_armed.seed") === -1) { vn.push("dev_jump_loop_armed.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "part_held", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "part_installed", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "coin", "set", 120.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);setup.applyAndNotifyTrait("player", null, "feed_line_days", "set", 3.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "parts_loop_open", "set");<</script>>
[[Into the market.->Location_underworld_market]]<p>Dev jump: seeding The Leash through the print — the berth rented, the file read, Mercer found under his new name, the arrangement back on, and the print already off his hand. Dropping at the breaking-dock with the read still to come. Kess keeps 10:00-22:00; Mercer keeps 23:00-08:00.</p>
<<set $game_state.current_canvas = "dev_jump_parts_loop">>
<<set $game_state.current_node = "dev_jump_parts_loop.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_parts_loop");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_parts_loop.seed") === -1) { vn.push("dev_jump_parts_loop.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "repair_session", "set", 12.0, false, null);setup.applyAndNotifyTrait("player", null, "colm_drains_done", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "case_progress", "set", 6.0, false, null);setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "coin", "set", 120.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);setup.applyAndNotifyTrait("player", null, "feed_line_days", "set", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "part_held", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "part_installed", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "mercer_attempts", "set", 0.0, false, null);setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "set", 15.0, false, null);setup.applyAndNotifyTrait("npc", "npc_kess", "relation", "set", 10.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "renner_drained", "set");setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");setup.applyAndNotifyFlag("player", null, "crew_known", "set");setup.applyAndNotifyFlag("player", null, "bastien_found", "set");setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");setup.applyAndNotifyFlag("player", null, "captivity_done", "set");setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");setup.applyAndNotifyFlag("player", null, "kess_met", "set");setup.applyAndNotifyFlag("player", null, "salvage_done", "set");setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");setup.applyAndNotifyFlag("player", null, "calloway_met", "set");setup.applyAndNotifyFlag("player", null, "calloway_believes", "set");setup.applyAndNotifyFlag("player", null, "case_insider_seen", "set");setup.applyAndNotifyFlag("player", null, "case_curated_seen", "set");setup.applyAndNotifyFlag("player", null, "pipe_known", "set");setup.applyAndNotifyFlag("player", null, "colm_found", "set");setup.applyAndNotifyFlag("player", null, "access_problem_seen", "set");setup.applyAndNotifyFlag("player", null, "docs_retrieved", "set");setup.applyAndNotifyFlag("player", null, "archive_1a_done", "set");setup.applyAndNotifyFlag("player", null, "controller_held", "set");setup.applyAndNotifyFlag("player", null, "berth_home", "set");setup.applyAndNotifyFlag("player", null, "file_shape_known", "set");setup.applyAndNotifyFlag("player", null, "print_needed", "set");setup.applyAndNotifyFlag("player", null, "mercer_found", "set");setup.applyAndNotifyFlag("player", null, "mercer_hospitality_open", "set");setup.applyAndNotifyFlag("player", null, "owner_print_taken", "set");setup.applyAndNotifyFlag("player", null, "parts_loop_open", "unset");<</script>>
[[Into the berth.->Location_kess_berth]]<p>Dev jump: seeding the post-close state (file + controller in hand, both locked; Spire sealed) and dropping in the underworld. Step into the breaking-dock off the strip to reach Kess.</p>
<<set $game_state.current_canvas = "dev_jump_1b_start">>
<<set $game_state.current_node = "dev_jump_1b_start.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_1b_start");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_1b_start.seed") === -1) { vn.push("dev_jump_1b_start.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "repair_session", "set", 12.0, false, null);setup.applyAndNotifyTrait("player", null, "colm_drains_done", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "case_progress", "set", 6.0, false, null);setup.applyAndNotifyTrait("player", null, "coin", "set", 50.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "renner_drained", "set");setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");setup.applyAndNotifyFlag("player", null, "crew_known", "set");setup.applyAndNotifyFlag("player", null, "bastien_found", "set");setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");setup.applyAndNotifyFlag("player", null, "captivity_done", "set");setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");setup.applyAndNotifyFlag("player", null, "kess_met", "set");setup.applyAndNotifyFlag("player", null, "salvage_done", "set");setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");setup.applyAndNotifyFlag("player", null, "calloway_met", "set");setup.applyAndNotifyFlag("player", null, "calloway_believes", "set");setup.applyAndNotifyFlag("player", null, "case_insider_seen", "set");setup.applyAndNotifyFlag("player", null, "case_curated_seen", "set");setup.applyAndNotifyFlag("player", null, "pipe_known", "set");setup.applyAndNotifyFlag("player", null, "colm_found", "set");setup.applyAndNotifyFlag("player", null, "access_problem_seen", "set");setup.applyAndNotifyFlag("player", null, "docs_retrieved", "set");setup.applyAndNotifyFlag("player", null, "archive_1a_done", "set");setup.applyAndNotifyFlag("player", null, "controller_held", "set");setup.applyAndNotifyFlag("player", null, "berth_home", "unset");<</script>>
[[Into the Reach.->Location_underworld_strip]]<p>Dev jump: seeding the post-Salvage state (Leash: Uncut, Calloway dispatched) and dropping at the Spire. Step into Vance Securities to open the Archive.</p>
<<set $game_state.current_canvas = "dev_jump_archive_start">>
<<set $game_state.current_node = "dev_jump_archive_start.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_archive_start");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_archive_start.seed") === -1) { vn.push("dev_jump_archive_start.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "repair_session", "set", 12.0, false, null);setup.applyAndNotifyTrait("player", null, "calloway_drains_done", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "coin", "set", 100.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 100.0, false, null);setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "renner_drained", "set");setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");setup.applyAndNotifyFlag("player", null, "crew_known", "set");setup.applyAndNotifyFlag("player", null, "bastien_found", "set");setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");setup.applyAndNotifyFlag("player", null, "captivity_done", "set");setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");setup.applyAndNotifyFlag("player", null, "kess_met", "set");setup.applyAndNotifyFlag("player", null, "salvage_done", "set");setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("cover_analyst"); setup.equipItem("cover_analyst");setup.showEffectNotification();<</script>>
[[To the Spire.->Location_spire_plaza]]<p>Dev jump: seeding a post-captivity state and dropping on the waterfront. The Salvage cold-open fires next.</p>
<<set $game_state.current_canvas = "dev_jump_salvage_start">>
<<set $game_state.current_node = "dev_jump_salvage_start.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_salvage_start");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_salvage_start.seed") === -1) { vn.push("dev_jump_salvage_start.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "core_strain", "set", 96.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 80.0, false, null);setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "renner_drained", "set");setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");setup.applyAndNotifyFlag("player", null, "crew_known", "set");setup.applyAndNotifyFlag("player", null, "bastien_found", "set");setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");setup.applyAndNotifyFlag("player", null, "captivity_done", "set");<</script>>
[[Onto the dock.->Location_the_waterfront]]<p>Dev jump: seeding a near-broken captivity state and dropping into the cell. Lie down once to tip the break.</p>
<<set $game_state.current_canvas = "dev_jump_captivity_break">>
<<set $game_state.current_node = "dev_jump_captivity_break.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_captivity_break");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_captivity_break.seed") === -1) { vn.push("dev_jump_captivity_break.seed"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_strain", "set", 95.0, false, null);setup.applyAndNotifyTrait("player", null, "energy", "set", 30.0, false, null);setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "renner_drained", "set");setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");setup.applyAndNotifyFlag("player", null, "crew_known", "set");setup.applyAndNotifyFlag("player", null, "bastien_found", "set");setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");<</script>>
[[Into the cell.->Location_captive_room]]<p>Dev jump: seeding the hunt chain and dropping into the grab.</p>
<<set $game_state.current_canvas = "dev_jump_bastien_grab">>
<<set $game_state.current_node = "dev_jump_bastien_grab.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_bastien_grab");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_bastien_grab.seed") === -1) { vn.push("dev_jump_bastien_grab.seed"); }<</script>>
<<nobr>>
<<link "Jump to the grab" "Canvas_hunt_the_grab_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "set", 60.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_fucked_once", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_anal_once", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_leads_extracted", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "brothel_hired", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "crew_known", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_found", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Dev jump: seeding the drain state and dropping into the payload.</p>
<<set $game_state.current_canvas = "dev_jump_renner_drain">>
<<set $game_state.current_node = "dev_jump_renner_drain.seed">>
<<script>>setup.markCanvasTriggered("dev_jump_renner_drain");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("dev_jump_renner_drain.seed") === -1) { vn.push("dev_jump_renner_drain.seed"); }<</script>>
<<nobr>>
<<link "Jump to the drain" "Canvas_renner_control_canvas_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drains_done", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "set", 60.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "opening_done", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_fucked_once", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_anal_once", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_leads_extracted", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><img src="./videos/scenes/the_two_men.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Cain stops in the lane about four feet short of the side door and stands there long enough that she thinks he is going to turn round. Then he goes in ahead of her, which surprises her.</p><span id="cascade-b2-beat-0"><p>Grier is in the chair with the glass on the arm of it. He looks up, and he takes about two seconds, and then he puts the glass down on the floor beside him and sits forward, and nine years comes up out of him all at once and does not spill.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Well.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Let him start.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years, and it takes a girl on an errand. You could have come down this lane any day of any of them. It is forty minutes. I have watched men with no legs make forty minutes.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I know how far it is.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Let him have it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> You have got the thing you asked me for. You have had it nine years. Do you know what I have got? That wall, with the outlines still on it, because I could not sell the tools and I could not use them either, and a lung that whistles, and this chair.</div></div><p>Cain does not defend any of it. He stands inside the door with his coat still on and lets it come, and does not once look at the wall with the outlines on it. That is the only thing in the room she has never seen him not look at.</p><span id="cascade-b2-beat-3"><<linkreplace "And the weapon.">><p>And then Grier gets to the thing he has been keeping, and he takes his time over it, and he watches Cain's face the entire way through in a manner she has seen used on men in a pit.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> You want to know what your errand girl has been doing down here for four months. She has been face down on that bench with her arse up taking it off me twice a week and asking politely for it, and she is better at it than anything else she does.</div></div><span id="cascade-b2-beat-4"><<linkreplace "He is not finished.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years I have had nothing whatsoever off you. Not a letter, not a coin, not a man at the door. And I have had that, twice a week, on the bench you left me with. Look at me while I say it. I have waited a very long time to say it and you are going to look at me.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Watch his face.">><p>Cain looks at him. He does not answer it and he does not look away and he does not do anything at all with his face. Except that something goes out of it, the way it goes out of a window when somebody two streets over turns a light off.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Twice in a week. That is the second time she has watched that happen to him and she has no name for it either time, and she names things for a living.</div></div><span id="cascade-b2-beat-6"><<linkreplace "And then he gives it to them anyway.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> There. That is the whole of what I had. Nine years and one sentence, and it was worth about what you would think.</div></div><p>And then he picks the glass up off the floor and tells them the thing they came for, because he was a good man once, and this is the last of it he has got, and nobody in the room mistakes it for forgiveness.</p><span id="cascade-b2-beat-7"><<linkreplace "The third tray.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Three trays. I had two of them in my arms and I went out through the yard door, and the third went up the front in a case with a lock on it, carried by a man who did not speak to one person in that room.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Was the third one filled last.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Watch Grier hear that.">><p>Grier stops with the glass halfway up. It is the first time all evening that anything has happened on his face that he did not put there on purpose.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> It was. They had the other two done and shut and then they went back into her for that one, and it took another hour, and there was nobody in that room enjoying the hour.</div></div><span id="cascade-b2-beat-9"><<linkreplace "And he works it out.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nobody asks that. Nobody on this earth asks which one was filled last unless he already knows what went into it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Look at him, girl. He has known what is in that box since before you came down my lane the first time, and he has had you running up and down this city for four months and never said it.</div></div><span id="cascade-b2-beat-10"><<linkreplace "Ask him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What is in it.</div></div><p>And Cain, who has answered every question she has ever put to him accurately and coldly and without once making it easier than it was, takes longer over this than he has taken over anything.</p><span id="cascade-b2-beat-11"><<linkreplace "Let him answer.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> There was somebody in your life. They took him out of you and they kept him, and he is up in that tower in a box with a lock on it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> That is all of it you are getting from me today.</div></div><span id="cascade-b2-beat-12"><<linkreplace "Do the arithmetic.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Then whoever is at the top of that tower has had nine years to decide what a thing like that is worth, and has not sold it and has not burned it. You work out for yourself what a man is waiting for.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He is not hiding it. He has been holding it and waiting to see what walks into his building. She has been walking into one of his buildings all month with a bought face on and a card in her sleeve.</div></div><span id="cascade-b2-beat-13"><<linkreplace "Get out of his room.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Right. Out. Both of you, and do not bring him back down here, because I have got no second sentence and I would not waste it on him if I had.</div></div><p>He pours another one before they are through the door. She hears the neck of the bottle go against the glass twice, because his hand is shaking, and neither of them says anything about that either.</p><span id="cascade-b2-beat-14"><<linkreplace "Walk back up the lane.">><p>It is forty minutes back up to the water and he walks it in silence, on the outside of her the whole way, like it is reflex.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> There is a man in a box at the top of a tower who was in her life, and a stranger has had him for nine years. And there is a man walking beside her who has not spoken since a machinist told him what she does on a bench twice a week, and she cannot work out what is wrong with him. She has never once failed to work out what is wrong with anybody.</div></div>[[Go home.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_two_men">>
<<set $game_state.current_node = "cap_the_two_men.base">>
<<script>>setup.markCanvasTriggered("cap_the_two_men");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_two_men.base") === -1) { vn.push("cap_the_two_men.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "two_men_done", "set");<</script>><p>She spends most of a day on the strip asking after a man she cannot describe, to people who do not know her, about somebody with no name and no address and no trade anybody has ever seen him at. It goes exactly as well as it was always going to.</p><p>She comes back at dark and he is sitting on the end of her bunk with his coat over his knees, and she is so pleased to see him that she is halfway through the first sentence before she has got the door shut.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It worked. The second time. It worked and I have been going up and down that strip all day trying to find you to tell you.</div></div><p>He does not say anything to that. He moves his coat off his knees and puts it on the floor, which gives her the whole of the bunk, and waits.</p><span id="cascade-b2-beat-1"><<linkreplace "Start with the light.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Late afternoon. Coming in low from one side, on my face. It was warm and it was not the cradle and it was not that room, because that room has the window painted.</div></div><p>She is talking fast. She has never once in this game talked fast.</p><span id="cascade-b2-beat-2"><<linkreplace "The hands.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> My hands were the wrong size. Short. No seam under the jaw, nothing braced in the wrists. I had a knot and I could not get the knot and nobody did anything about it. Nothing happened because I could not do it. Nothing at all happened.</div></div><p>She says that part twice, the nothing happening, because it is the part she cannot get over.</p><span id="cascade-b2-beat-3"><<linkreplace "The neck.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> There was somebody behind me. Watching me get it wrong and not fixing it. And a hand came and rested on the back of my neck — not holding, resting — and the thumb went along the seam once. The seam that is not there yet.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And there was no fear in me anywhere. Not the flat kind. The other one.</div></div><span id="cascade-b2-beat-4"><<linkreplace "The name.">><p>And then she says it out loud, in her own room, to the only person in the world she would say it to, and it is the first time it has been in the air in nine years.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Vesper. It said, Vesper, you have got all afternoon.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Wait for him.">><p>He does not repeat it. He does not do anything with it at all. He sits on the end of the bunk with his hands loose between his knees and looks at a point on the floor about a foot in front of her boots.</p><span id="cascade-b2-beat-6"><<linkreplace "He asks about the face.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> The one behind you.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> No face. I turned to look and there was nothing there. Not a blur, not a shadow. An absence with a person's shape in it, like a field that never got written.</div></div><span id="cascade-b2-beat-7"><<linkreplace "He asks again.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Nothing at all. Not a build, not a height. Not a hand you had seen before.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Nothing at all. It is the one hole in it and everything round the hole is perfect.</div></div><p>She is still pleased. She says the word perfect and she means it about the file.</p><span id="cascade-b2-beat-8"><<linkreplace "And it falls out of him.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> You don't remember me at all?</div></div><span id="cascade-b2-beat-9"><<linkreplace "Answer him.">><p>And she answers it the way she has answered every question anybody has ever asked her. That is accurately.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You are not in it. It is a childhood. It would not have you in it. Piece two is the making and piece one is before any of that, so there is nothing in either of them that could have you in it.</div></div><span id="cascade-b2-beat-10"><<linkreplace "Wait for him to say the next part.">><p>There is no next part. He looks at the floor for a while longer and then he picks his coat up off it and stands, and it takes him two goes, and she has never seen anything take him two goes.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> No. It would not.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Watch him go.">><p>He gets to the door and stops in it the way he stopped in a doorway two nights ago, and does not turn round, and says the thing he came to say instead of the thing that happened.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> There is a third piece. You have got a hole in a file and somebody put it there on purpose. Go and ask the old man what went out of that room in the third tray.</div></div><span id="cascade-b2-beat-12"><<linkreplace "And then the room.">><p>Then he is gone down the boards and she is standing in her own room with her coat still on, holding the best thing that has ever happened to her, and something has gone wrong in here and she cannot find it.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She has run four men in one week off nothing but their breathing. She reads a room the way other people read a clock. And she has no idea, none at all, what just happened in this one.</div></div>[[Sit down on the bunk.->Location_the_cot]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_question">>
<<set $game_state.current_node = "cap_the_question.base">>
<<script>>setup.markCanvasTriggered("cap_the_question");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_question.base") === -1) { vn.push("cap_the_question.base"); }<</script>>
<<script>>advanceTime(45);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "cain_absent_confirmed", "set");<</script>><p>The same twenty minutes with her head down and the same two changes of direction, and afterwards she could still only guess at it on a map.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> The difference is entirely on her side of it. Last time she was brought. This time she asked.</div></div><span id="cascade-b2-beat-0"><p>Different men. Five of them, none of them the four from before, and not one of them looks up when she comes through the door either. The window is still painted over. Somebody has moved the couch.</p><span id="cascade-b2-beat-1"><<linkreplace "Give him the drain.">><p>She has it in his hand before he has got his own hand up for it. He puts it in his coat and says nothing about her having got there first.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Last thing and then I am out of your way. Do not try to do it. You cannot do it. You can only be here while it does or does not happen to you.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Watch him go.">><p>The door goes to behind him and he stops on the landing the way he stopped on it before, and stays, and does not come down and does not go up.</p><span id="cascade-b2-beat-3"><<linkreplace "Let them start.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_capstone_fire_open_t5"] to ($game_state.media_cycle["sex_capstone_fire_open_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_capstone_fire_open_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_capstone_fire_open_t5"]>><<if _mc is 0>><video src="./videos/sex/capstone_fire_open_t5/c2a491505ee.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/capstone_fire_open_t5/c3bffb47f4e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/capstone_fire_open_t5/c5d9dd1bb3e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/capstone_fire_open_t5/cb1791f0c0c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>It starts the same way. Somebody moves her where they want her, somebody else gets her clothes off, and inside about a minute there is a cock in her mouth and a hand spreading her open from behind.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Shift the ashtray off there before somebody puts a knee in it.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Catch yourself doing it.">><p>And she is working. No gap at all. Reading the breathing above her, holding him at the top of the stroke, hips back on the beat for the one behind. Her body ran the operator before she had her knees under her.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> There it is. Nine years of it. She could no more not do this than not blink.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Do not correct it.">><p>So she does not fight it and she does not fix it. She lets her mouth go lazy and her timing go wrong and the man above her put his hand in her hair and take over, and she is worse at this than she has been since she was made.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Just hold still, love. I will do it.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Stop wanting it.">><p>And somewhere under the third man she puts the whole thing down, and goes on lying there being used while nothing happens.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Not the working. The wanting. Nothing is going to come up out of her tonight and she is going to be here anyway, and that is the end of it.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Let them have it.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_capstone_fire_use_t5"] to ($game_state.media_cycle["sex_capstone_fire_use_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_capstone_fire_use_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_capstone_fire_use_t5"]>><<if _mc is 0>><video src="./videos/sex/capstone_fire_use_t5/c6ea5fc4338.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/capstone_fire_use_t5/c66e6553afe.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/capstone_fire_use_t5/cb4e0649020.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/capstone_fire_use_t5/ccf9f8213a4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>They take turns and they take their time. She is fucked in her cunt and in her mouth and in her ass by men whose faces stay a blur, and none of it is for anything, and she does not once try to make any of it go faster or better or longer.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> You had her twice.</div></div><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Nobody is counting. Go if you are going.</div></div><span id="cascade-b2-beat-8"><<linkreplace "And the room goes quiet.">><p>There is a cock moving in her and a weight on her back, and neither of them is being answered.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> The thing that counts has stopped counting. The file is not open. Nowhere in the whole of her is anybody planning, angling, measuring, reading or getting.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Nobody home.</div></div><span id="cascade-b2-beat-9"><<linkreplace "And then.">><p>And then the light changes.</p><p>Late in the afternoon, coming in low from one side, warm on the side of her face. Not the cradle's light and not this room's, because this room's window is painted over.</p><span id="cascade-b2-beat-10"><<linkreplace "Look at your hands.">><p>She is small. The hands in front of her are the wrong size. Short fingers, no seam under the jaw, no bracing in the wrists. She has been given something to do with them and she is doing it badly.</p><p>It is a knot. She cannot get the knot. She has been failing at it for a while and nothing whatever has happened as a result.</p><span id="cascade-b2-beat-11"><<linkreplace "Somebody is behind you.">><p>Somebody is behind her, close, watching her do it wrong and not reaching past her to do it right. The breathing is not waiting for anything.</p><p>A hand comes to rest on the back of her neck. Not steering her, not holding her. Resting. The thumb moves once, slowly, along the seam that is not there yet.</p><span id="cascade-b2-beat-12"><<linkreplace "No fear anywhere.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> And there is no fear in her. Not the permitted absence of it, not the grey nothing the company installs and calls composure. The other kind. The kind that is not present because there is nothing in the room that could hurt her.</div></div><span id="cascade-b2-beat-13"><<linkreplace "The voice.">><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Vesper. You have got all afternoon.</div></div><span id="cascade-b2-beat-14"><<linkreplace "Turn round.">><p>She turns her head to look and there is nothing to look at. Not a blur and not a shadow. An absence with the exact shape of a person in it, the way a file reads when the field was never written.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Vesper.</div></div><span id="cascade-b2-beat-15"><<linkreplace "Come back.">><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> She is miles away. Look at her.</div></div><p>The afternoon closes and the room comes back all at once. The painted window, the mattress, a hand on her hip, somebody finishing on the small of her back and somebody else moving up to take his place. It has not stopped for any of it.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_capstone_fire_finish_t5"] to ($game_state.media_cycle["sex_capstone_fire_finish_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_capstone_fire_finish_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_capstone_fire_finish_t5"]>><<if _mc is 0>><video src="./videos/sex/capstone_fire_finish_t5/c0e0385a75b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/capstone_fire_finish_t5/c76cf067a00.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/capstone_fire_finish_t5/c769d4bcbbb.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/capstone_fire_finish_t5/cfae7453d4c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><span id="cascade-b2-beat-16"><<linkreplace "Let it end.">><p>They finish and they are done and they go, one and then another. Somebody turns the light on.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Leave it on. He is coming back up for her in a minute.</div></div><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Right. Is anybody going past the bridge, because I am not walking it.</div></div><p>Nobody has said a word to her since the man who told her to hold still.</p><span id="cascade-b2-beat-17"><<linkreplace "Lie there.">><p>She lies on the mattress in the room with the painted-over window with cum on her back and her thighs and her face, and she does not move for a long time, and she is not doing anything at all.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Vesper. Somebody stood behind a small girl who could not tie a knot and had all afternoon to not tie it in, and called her that, and was not in a hurry about any of it.</div></div><span id="cascade-b2-beat-18"><<linkreplace "The door.">><p>The door goes and it is him with her coat again. He looks at her face and stops in the doorway, and whatever he finds there he does not say a word about, and he holds the coat open for her instead of handing it over.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> There is a tap on the landing. Use it before we go down, it is a long way in a car.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She does not tell him. Not in this room, not in his coat, not on the stairs. It is the first thing in nine years that is hers and she is not putting it down where somebody else can pick it up.</div></div>[[Let him take you home.->Location_the_cot]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_capstone_fire">>
<<set $game_state.current_node = "cap_capstone_fire.base">>
<<script>>setup.markCanvasTriggered("cap_capstone_fire");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_capstone_fire.base") === -1) { vn.push("cap_capstone_fire.base"); }<</script>>
<<script>>advanceTime(300);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "vesper_named", "set");<</script>><p>She does not get told where. Twenty minutes in the back of something with her head down and two changes of direction, the way she went to his lab the first time. Except this time she is not carrying anything and there is nothing at the other end of it she is meant to come away with.</p><span id="cascade-b1-beat-0"><p>Warm, low, a couch along one wall and a mattress on the floor under a window somebody painted over. Four men in it. Not one of them looks up when she comes through the door, and nobody asks her anything at all.</p><span id="cascade-b1-beat-1"><<linkreplace "He holds his hand out.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> The drain. You will not need it, and you will reach for it, and I would rather you reached into a pocket that was empty than found it there and used it.</div></div><p>She puts it in his hand. It is the first time in two years anything has come off her that she did not take off herself.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Nobody in here knows your name and none of them will ask. There is nothing in here to get. That is the whole specification of the room and it was not easy to find one.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Watch him go.">><p>He goes out and pulls the door to behind him and the door does not lock, and she hears him stop on the landing and not go any further down. Then nothing. Then somebody on the couch says something to somebody else that is not about her.</p><span id="cascade-b1-beat-3"><<linkreplace "Let them start.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_capstone_fail_open_t5"] to ($game_state.media_cycle["sex_capstone_fail_open_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_capstone_fail_open_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_capstone_fail_open_t5"]>><<if _mc is 0>><video src="./videos/sex/capstone_fail_open_t5/c2c40566fa7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/capstone_fail_open_t5/c5c95d9dfbb.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/capstone_fail_open_t5/c5dc938619c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/capstone_fail_open_t5/ca3da171ea7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>One of them takes her arm above the elbow and moves her, not hard, the way you move a thing that is in the way. Her coat goes on the arm of the couch and somebody else's hands get the rest of it off her.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> She the one he rang about?</div></div><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Does it matter.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Take him in your mouth.">><p>She goes down on the mattress with a cock in her mouth and a second man getting her knees apart behind her, and there is no negotiation anywhere in it. She is simply where the two of them have decided she is going to be.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Turn her round a bit. I cannot get at her like that.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Read him.">><p>And she reads him. His breathing goes shallow at the top of the stroke, so she holds him there and works her tongue flat against the underside of him, and his hand shuts in her hair, and she has him. She can feel exactly how long he has left and she has adjusted twice already to make it longer.</p><p>The other one is in her cunt by then and she has started matching him, hips back on the beat, because a man who is being met takes longer.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> There we go. That is better.</div></div><span id="cascade-b1-beat-6"><<linkreplace "Both of them.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_capstone_fail_double_t5"] to ($game_state.media_cycle["sex_capstone_fail_double_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_capstone_fail_double_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_capstone_fail_double_t5"]>><<if _mc is 0>><video src="./videos/sex/capstone_fail_double_t5/c5b3ca81064.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/capstone_fail_double_t5/c5b33560030.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/capstone_fail_double_t5/c8ad82747f6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/capstone_fail_double_t5/ca8d5510985.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>They swap without asking and she goes with it, and then there are hands on her hips from behind and a third one standing over her waiting his turn with his cock already out, and she is keeping all of it moving.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> I am not finished.</div></div><span id="cascade-b1-beat-7"><<linkreplace "Reach for it.">><p>Somewhere in the middle of it her hand goes back and down to the flat of her own hip, to the pocket where it lives, and closes on cloth and her own thigh under the cloth and nothing else at all.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She did not decide to do that. Her hand went and got it and her hand had not been told.</div></div><span id="cascade-b1-beat-8"><<linkreplace "Try to stop.">><p>So she stops. Hands slack, hips still, the one behind her doing the whole of the work, and she holds it with her cheek on the mattress and her eyes shut for as long as she can.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> And she is counting. How long she has held it, and checking, and pleased with the number. Running the whole thing like a job, with the job being not to have one.</div></div><span id="cascade-b1-beat-9"><<linkreplace "Let them finish.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_capstone_fail_finish_t5"] to ($game_state.media_cycle["sex_capstone_fail_finish_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_capstone_fail_finish_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_capstone_fail_finish_t5"]>><<if _mc is 0>><video src="./videos/sex/capstone_fail_finish_t5/c0b54fa55c7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/capstone_fail_finish_t5/c06020d24fa.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/capstone_fail_finish_t5/ca178155934.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/capstone_fail_finish_t5/cd4c7b648a2.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>They finish on her and in her, one after another, and there is nothing said about any of it. The last one is off the mattress and doing his belt before she has got her breath back.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Is there anything left in that bottle or did you finish it.</div></div><p>None of them looks at her face on the way out of the room.</p><span id="cascade-b1-beat-10"><<linkreplace "Wait for it.">><p>She lies on the mattress in a room she cannot name with her heart coming down and cum drying on her, and she waits, and she is still waiting when the light through the painted window has changed.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> No room. No table. No hand at the back of her neck. She worked four strangers who wanted nothing off her, and she was very good at it, and that was the one thing she was not supposed to be.</div></div><span id="cascade-b1-beat-11"><<linkreplace "The door.">><p>The door goes and it is him, on his own, with her coat over his arm. He looks at her for about as long as it takes and does not ask, because he has never once had to ask her anything.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Again, then.</div></div>[[Let him take you home.->Location_the_cot]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_capstone_fail">>
<<set $game_state.current_node = "cap_capstone_fail.base">>
<<script>>setup.markCanvasTriggered("cap_capstone_fail");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_capstone_fail.base") === -1) { vn.push("cap_capstone_fail.base"); }<</script>>
<<script>>advanceTime(240);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "capstone_failed", "set");<</script>><img src="./videos/scenes/cain_sits_down.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He is sitting down. Three times he has been in this room and three times he has been standing at the feed line with his coat on, and this time he is on the edge of the bunk with his forearms on his knees, looking at the floor.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Your hands stopped.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> They did.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I have been hoping I was wrong since the first one. I stopped being able to hope it at the second one. That is the whole of what my hands were doing and you were not supposed to be able to see it.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Let him say it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> They are both in you. Seated, intact, and I have checked both seats twice, because I would very much rather it had been the seat.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> They are not coming up because you never stop.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Tell him that is not true.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I have been fucked in every room in this city. A depot office. A penthouse. A back room under a bar. A bench in the Reach and a bench in a tower. If stopping were the trick I would have had all three of them back a year ago.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Name one of them where you were not working.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Try to.">><p>She goes down the list. There is a cover on her in most of them. In the rest there is a mark in front of her, or a weapon on her, or a thing she is there to take out of the back of a man's head, and in two of them all three at once.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Every single time. You have never once been fucked without a job on, and a body doing a job does not put anything down. It cannot. That is what it is for.</div></div><span id="cascade-b2-beat-4"><<linkreplace "There was one.">><p>There was one. On her back on the floor of a room she could not leave, with men on the other side of the door and nothing at all left in her, and nothing whatsoever in that room to get.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "glitch_iii_seen", "operator": "is_true"}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Something came up on its own. A hand at the back of my neck and no fear in me anywhere, and I still do not know whose it was.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "glitch_iii_seen", "operator": "is_false"}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It was the only time anything in me has ever moved on its own. I did not go looking for it and there was nothing in that room I could have been trying to get.</div></div>
<</if>><p>He does not ask her what it was. He does not ask a single question about it, and he is a man who asks about everything, and it goes past both of them without either of them touching it.</p><span id="cascade-b2-beat-5"><<linkreplace "So what is the price.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> It is not a bed and it is not a room and it is not me. It is being used by people who want nothing off you and will not remember you afterwards. No name, no cover, no angle, nothing on you anybody is trying to get.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> You cannot decide to stop. Nobody can. You can only be somewhere that stopping is the only thing left to do.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I take you and I go. I am not standing in a room watching that happen to you. I will be outside it and I will come back for you. That is a thing I have done once already unasked.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Ask him if it works.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And if nothing comes up.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Then nothing comes up, and you go on carrying two clean files about a stranger. I told you the mechanical part was done. It was done. It got you nothing and I am not doing that to you a second time.</div></div><p>Then he stands up, and puts the chair back where the chair lives, and goes, and he does not ask her for an answer on his way out because he has not asked her a question.</p>[[Sit with it.->Location_the_cot]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_price">>
<<set $game_state.current_node = "cap_the_price.base">>
<<script>>setup.markCanvasTriggered("cap_the_price");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_price.base") === -1) { vn.push("cap_the_price.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "price_named", "set");<</script>><p>She gets into the frame unasked and puts her arms where the arms go. Nobody says anything about her doing that. The mirror puts her own hands in front of her the way it did the first time.</p><span id="cascade-b1-beat-0"><p>He is faster than he was. The case off rack four goes onto the bench beside him, still cold from two floors under a tower.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Different slot. Same seat. You will not feel this one either and I would rather you knew that going in than found it out standing there.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Let him seat it.">><p>It goes home lower down and further back than the first one did, a pressure behind the jaw rather than the skull, and she knows the shape of the feeling now well enough to recognise it arriving and to recognise it stopping.</p><span id="cascade-b1-beat-2"><<linkreplace "Wait for it.">><p>She waits for less time than she did the first time. That is a thing about herself that she notices and files, and then stops, because there is plainly nothing coming.</p><p>No room. No table. No hands, no voice, no year. A pressure behind the jaw that has already stopped.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Both of them in. That is the whole of the mechanical part and it is done.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Tell him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Nothing again.</div></div><p>In the glass his hands stop. Both of them, over the tray, holding nothing. He does not look up, and the stopping goes on for about two seconds.</p><p>Then his hands start again and put the tray straight, and he goes on putting the tools back where the tools live.</p><span id="cascade-b1-beat-4"><<linkreplace "Ask him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What was that.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Get your arms out of the cradles.</div></div><p>That is all of it. Not a refusal and not an answer. An instruction, given in the voice of a man doing the next thing on a list he wrote before she got here.</p><span id="cascade-b1-beat-5"><<linkreplace "Get out of the frame.">><p>He hands her the coat off the end of the bench. The lining she has been keeping a case in for a day and a half lies flat, and there is nothing in either pocket, and he is already turned away.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Two seconds of a man's hands not moving. She has watched him work twice now and that is the only time either of them has stopped. He thinks he has done it wrong. He has not done it wrong. She would have felt that.</div></div>[[Out.->Location_underworld_strip]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_install_two">>
<<set $game_state.current_node = "cap_install_two.base">>
<<script>>setup.markCanvasTriggered("cap_install_two");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_install_two.base") === -1) { vn.push("cap_install_two.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "pieces_seated", "add", 1.0, false, null);setup.showEffectNotification();<</script>><p>She has her coat on before she has finished coming down the boards, because he is at the feed line again and she has started expecting it, which she notices and does not enjoy noticing.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It is a company sample and there is a clock on it. The day somebody opens what I left on that shelf and reads it, my name is in a book.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Then it holds until it does not. That is every arrangement anybody in this city has ever had, and yours has lasted eleven days longer than mine did.</div></div><span id="cascade-b1-beat-1"><<linkreplace "He is not interested in the clock.">><p>He asks her nothing about the tower. Not the room, not the man, not the log. He takes the case, reads the eleven characters off the end of it, and holds the door.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Head down. You know the shape of it by now, and it does not get shorter for knowing.</div></div>[[Go with him.->Location_cain_lab]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cain_comes_third">>
<<set $game_state.current_node = "cain_comes_third.base">>
<<script>>setup.markCanvasTriggered("cain_comes_third");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cain_comes_third.base") === -1) { vn.push("cain_comes_third.base"); }<</script>>
<<script>>advanceTime(45);<</script>><img src="./videos/scenes/the_swap.webp" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The log is a book on a stand, pen on a string. She writes the name off her card, the hire number, the time. A reader who signs the book is a reader. A reader who does not is a question.</p><span id="cascade-b2-beat-0"><p>The racks go six deep and the cold comes off them in a sheet. Every case on every shelf is the same grey case with a different label on the end of it.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Which is not luck. Nobody buys forty different cases, and that is the only reason Kess could match one off a hull in an afternoon.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Rack four.">><p>Rack four, second shelf, third from the left, exactly where a man who has signed a thing out eleven times and back in keeps it. The eleven characters are the eleven she took out of the back of his head.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She has never seen this object before in her life, and she has been inside the room it was made in.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Read the dial.">><p>There is a dial on the front of the cabinet and the dial is the only thing in this room that anybody in this building looks at. It reads the number Kess made her say back to him twice.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A dial has no memory. It does not record that it was opened; it reports what it is reading now. So there is no window to be quick inside of. There is only the needle, and the needle is slower than her hands.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Make the exchange.">><p>The blank comes out of the coat lining in one hand and rack four's case comes off the shelf in the other, and the cold comes off both of them at once.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Four seconds with a company sample in each fist. There is no version of that which could be explained to anybody at all.</div></div><p>Then the blank is on the shelf, third from the left, label out, and the door is shut on it, and the needle has not come off the number.</p><span id="cascade-b2-beat-4"><<linkreplace "Count them twice.">><p>She counts the characters on the case she has left behind. Eleven. She counts them again, because a man in a flooded dock told her to, and because he told her he had once done nine and been certain it was eleven.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Eleven is the last thing anybody will ever check about that case, and the man who checks it will be checking a number he already knows the answer to.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Sign out.">><p>She signs out. The time, in the box, four minutes after the time in the box above it, in the same handwriting, with the same pen on the same string.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> This is why it had to be a swap. A book that says a reader went into a room where nothing is missing says a reader went into a room. The morning something is gone, the same book says her name.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Walk out with it.">><p>The real one goes into the lining where the blank was. The coat hangs the way it hung coming in, and the stairwell is the same open concrete going up as it was coming down, and nobody passes her on it.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A recording of her own making, in a coat lining, going up a stairwell. It holds a dial forever. It holds a man exactly until one of them opens it and reads it, and she does not get told how long that is.</div></div>[[Back to the desk.->Location_the_rise_floor]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_swap">>
<<set $game_state.current_node = "cap_the_swap.base">>
<<script>>setup.markCanvasTriggered("cap_the_swap");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_swap.base") === -1) { vn.push("cap_the_swap.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "piece_two_held", "set");<</script>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_finish_anal_t5"] to ($game_state.media_cycle["sex_sabin_finish_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_finish_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_finish_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_finish_anal_t5/c60d0e5433b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_finish_anal_t5/c69da5a83cf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_finish_anal_t5/c731ccd7fd4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_finish_anal_t5/cd223db7ea6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>What comes down her arm out of a man four months into a job is not nine years of anything. It is a filing system with a person operating it, and every single item in it is exactly where he put it.</p><span id="cascade-b2-beat-0"><p>A morning in April. A courier in the lobby with a case the size of a lunch box and a clipboard, and Sabin signing for it one-handed with the mug still in the other, because nobody had told him it was anything.</p><p>Four items in the case. Three of them he has had open on that bench since. The fourth has a reference on it, a temperature range, and no other writing anywhere on it at all.</p><span id="cascade-b2-beat-1"><<linkreplace "Read the reference.">><p>Eleven characters, and he knows them the way a man knows a phone number he never sat down to learn. She has them out of him before he has finished remembering them.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Building, floor, rack, line. Not what it is. He has never once been curious about what it is, and that is the only reason it has sat there safely for four months.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Follow it down.">><p>Two floors under the lab. A room with a door that logs, and a cold cabinet against the back wall running off the one circuit in this building nobody is allowed to switch off. Rack four, second shelf.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> How often do you go down there.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Eleven times out and eleven times back. It is the most careful I have ever been about anything in my life and it is entirely because of the temperature range. Nothing else about it interests me.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Ask him what it is.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What is on the fourth item.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> A capture. Somebody's, off the programme. I do not need to know whose. I need the method, and the method is in how it was taken. Not in what it says.</div></div><p>He answers evenly, the way men answer in this state, with no idea whatever that he is answering.</p><span id="cascade-b2-beat-4"><<linkreplace "Whose.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> It is a recording of her being made. It has been in a cabinet two floors under that bench the whole time she has been at a desk one floor below it, reading his filing for fifteen coin a day.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Come out of it.">><p>It lets go all at once and she is on the bench with her mouth still open against his hand and his weight coming down slow onto her back. He takes the hand away and apologises for it, which he does every time.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Sorry. Was that too. No. All right. Good.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Work out what you have.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> The door logs and the item is signed for, and the man who signs for it checks a temperature and nothing else. She cannot take it off that shelf. She can only put something else on it.</div></div>[[Get dressed.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "sabin_drain_canvas">>
<<set $game_state.current_node = "sabin_drain_canvas.d0">>
<<script>>setup.markCanvasTriggered("sabin_drain_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("sabin_drain_canvas.d0") === -1) { vn.push("sabin_drain_canvas.d0"); }<</script>><p>The drain fires the way it fires now, with nothing new left in it to find. Four more months of his week coming loose across her palm and the evening going soft behind his eyes while he is still inside her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> ...Mm. Was I saying something. I was saying something. There is an hour of my own handwriting here that I do not remember doing.</div></div>
<<set $game_state.current_canvas = "sabin_drain_canvas">>
<<set $game_state.current_node = "sabin_drain_canvas.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("sabin_drain_canvas.done") === -1) { vn.push("sabin_drain_canvas.done"); }<</script>>
[[Leave it there.->Location_sabin_lab]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_finish_facial_t5"] to ($game_state.media_cycle["sex_sabin_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_finish_facial_t5/c68f4bb2d43.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_finish_facial_t5/c943a9a1842.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_finish_facial_t5/cc2ef54d54d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_finish_facial_t5/ce34e41d7d6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He comes out of her mouth and finishes on her face with his fist shut in her hair, and makes a sound at the end of it that he is visibly annoyed with himself about. Nothing comes loose but him. The drain only opens the one way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Sorry. Sorry, that was loud. There is nobody in the building. There is nobody in the building and I still did that.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_finish_inside_t5"] to ($game_state.media_cycle["sex_sabin_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_finish_inside_t5/c38eb32ba80.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_finish_inside_t5/ca9c4b0e8e6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_finish_inside_t5/cddbb2c65ee.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_finish_inside_t5/cec1619684c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes inside her on the bench with both hands under her thighs holding her open, and stays in her while it goes with his forehead down on her sternum. She has taken nothing. Not this way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Give me a minute. I am nearly forty and that is a workbench, and I have three hours of somebody's handwriting left to get through tonight.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<p>He finishes in her ass and the drain opens under it the way it is built to. The shudder cracking him wide, her mouth still shut against his palm, four months of him starting to come loose across her tongue.</p>
<</if>>
<<set $game_state.current_canvas = "loop_sabin_finisher">>
<<set $game_state.current_node = "loop_sabin_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_sabin_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_sabin_finisher.climax") === -1) { vn.push("loop_sabin_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Get dressed." "Location_the_waterfront">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_finisher:cc0");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Let it go — wrong gear." "Location_the_waterfront">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_finisher:cc1");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Let it go — the drain is empty. Take a night on the feed line at the berth and it reloads." "Location_the_waterfront">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_finisher:cc2");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_finisher:cc3') ? '' : 'unlocked-choice'">
<<link "Take what he carries." "Canvas_sabin_drain_canvas_Node_d0">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sabin_drains_done", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_finisher:cc3");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_finisher:cc4') ? '' : 'unlocked-choice'">
<<link "Drink him down again." "Canvas_sabin_drain_canvas_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_finisher:cc4");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "gte", "value": 1}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_sabin_finisher = [{"text": "Get dressed.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Let it go \u2014 wrong gear.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]}}, {"text": "Let it go \u2014 the drain is empty. Take a night on the feed line at the berth and it reloads.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]}}, {"text": "Take what he carries.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "lt", "value": 1}]}}, {"text": "Drink him down again.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "gte", "value": 1}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_sabin_finisher",
choices: window._engineNoExitsDiag_loop_sabin_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_sabin_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_sabin_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_loop_t4"] to ($game_state.media_cycle["sex_sabin_loop_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_loop_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_loop_t4"]>><<if _mc is 0>><video src="./videos/sex/sabin_loop_t4/c29b1ccde1b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_loop_t4/c747cc91f7e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_loop_t4/cb8eef41e69.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_loop_t4/cb367857587.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He takes the stacks off the bench two at a time and puts them on the floor in order. That is the only part of any of this he is careful about. Neither of them says what the bench is being cleared for. It stopped needing saying.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Ten seconds. I am not losing this pile again, and if it goes on the floor in the wrong order that is a Thursday I do not get back.</div></div><p>She is out of the kit before he has turned round, and the lights stay exactly as on as they always are.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> On the stool, not the bench. Put it on the stool. The bench is about to be busy and I am not explaining a missing skirt to anybody on a Tuesday.</div></div>
<<set $game_state.current_canvas = "loop_sabin_lab">>
<<set $game_state.current_node = "loop_sabin_lab.intro">>
<<script>>setup.markCanvasTriggered("loop_sabin_lab");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_sabin_lab.intro") === -1) { vn.push("loop_sabin_lab.intro"); }<</script>>
<<nobr>>
<<link "Down on your knees." "Canvas_loop_sabin_lab_Node_base_oral_sabin">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Up onto the bench." "Canvas_loop_sabin_lab_Node_base_vaginal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn round for him." "Canvas_loop_sabin_lab_Node_base_anal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_loop_oral_t5"] to ($game_state.media_cycle["sex_sabin_loop_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_loop_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_loop_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_loop_oral_t5/c6ec2b4b0ab.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_loop_oral_t5/c9227968d3d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_loop_oral_t5/cbec06ed5bb.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_loop_oral_t5/cd39a4bff28.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees on the concrete between him and the bench with his cock in her mouth and his hand resting on the back of her head, not pushing. He watches her do it. He always watches her do it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Slow. There is no hurry on this floor and there is nobody in this building. Look up at me while you do that. There. Like that, and keep doing that.</div></div>
<<set $game_state.current_canvas = "loop_sabin_lab">>
<<set $game_state.current_node = "loop_sabin_lab.base_oral_sabin">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_sabin_lab.base_oral_sabin") === -1) { vn.push("loop_sabin_lab.base_oral_sabin"); }<</script>>
<<nobr>>
<<link "Keep him in your mouth." "Canvas_loop_sabin_lab_Node_base_oral_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Up onto the bench." "Canvas_loop_sabin_lab_Node_base_vaginal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn round for him." "Canvas_loop_sabin_lab_Node_base_anal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_lab:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_sabin_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_lab:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_loop_vaginal_t5"] to ($game_state.media_cycle["sex_sabin_loop_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_loop_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_loop_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_loop_vaginal_t5/c3af08e4a8d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_loop_vaginal_t5/c366d3a86b3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_loop_vaginal_t5/c5142cc1b2d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_loop_vaginal_t5/ca9c4b0e8e6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her back on the bench with her heels up on the edge of it and his cock working into her cunt, and the steel is cold the whole length of her spine while none of the rest of her is.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> You have gone quiet again. I know you have to. I am telling you that I mind. That is not the same as asking you to stop.</div></div><p>She is wet enough that he can hear it over the vents and it is not a thing she decided to do. He shifts his grip under her thigh and goes in deeper for it and hears that too.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> And do not hold your breath. You go tight when you hold your breath. Breathe, and let me do this part.</div></div>
<<set $game_state.current_canvas = "loop_sabin_lab">>
<<set $game_state.current_node = "loop_sabin_lab.base_vaginal_sabin">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_sabin_lab.base_vaginal_sabin") === -1) { vn.push("loop_sabin_lab.base_vaginal_sabin"); }<</script>>
<<nobr>>
<<link "Let him have it." "Canvas_loop_sabin_lab_Node_base_vaginal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_loop_sabin_lab_Node_base_oral_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn over — give him your ass." "Canvas_loop_sabin_lab_Node_base_anal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_lab:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_sabin_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_lab:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_loop_anal_t5"] to ($game_state.media_cycle["sex_sabin_loop_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_loop_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_loop_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_loop_anal_t5/c2ab47c4e57.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_loop_anal_t5/c4fed926300.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_loop_anal_t5/ca2e1009dd5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_loop_anal_t5/ce331f40278.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Face down over the end of the bench with her ass up and his cock working into it by degrees, one hand spread flat on her lower back to keep her exactly where he put her. He does not stop talking while he does it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> All right. Breathe out for me. Out. There. That is it, that is all of it, and you are going to have to be very quiet about the next part.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Still talking, yes. I am aware. It is the only way I have of telling whether you are all right, given that you will not make a single sound about it.</div></div><p>Then his hand comes round and over her mouth the way it did the first night, and she opens against his palm and keeps her mouth there, wet on the heel of his hand. That is the seat. The thing that keeps her quiet is the thing the drain sits in.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Everything above the neck is hers and working. Everything below it stopped taking instructions somewhere around the second stroke, and she has decided not to look at that too closely.</div></div>
<<set $game_state.current_canvas = "loop_sabin_lab">>
<<set $game_state.current_node = "loop_sabin_lab.base_anal_sabin">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_sabin_lab.base_anal_sabin") === -1) { vn.push("loop_sabin_lab.base_anal_sabin"); }<</script>>
<<nobr>>
<<link "Take it." "Canvas_loop_sabin_lab_Node_base_anal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on him." "Canvas_loop_sabin_lab_Node_base_vaginal_sabin">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_sabin_lab:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — and take what he carries." "Canvas_loop_sabin_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_sabin_lab:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "lt", "value": 4}]})>>
<p>He does not stop working when she comes up the room. The bench is eleven years in stacks and he is somewhere in the middle of it, and he is talking before she is close enough to be talked to.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> There you are. Tell me why a man orders forty litres of a thing he only ever logs using two of. No — do not tell me. Read it first and then tell me.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 4}, {"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "lt", "value": 10}]})>>
<p>He has stopped saying what any of it is. Things get put into her hands on the assumption that she knows what they are for, and he has been right about that twice now without ever checking.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Second box. No, the one behind it. He was running two of these in parallel and calling them both by the same word. That is the entire reason nothing in this room adds up.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 10}, {"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "lt", "value": 14}]})>>
<p>They work the same three feet of bench now. He talks the whole time and half of it is not about the archive at all, and she has started answering the half that is not.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> You are the only person in this building I do not have to say a sentence to twice. I am aware of how that sounds coming from me. I have decided not to think about it very hard.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 14}]})>>
<p>The bench is clear when she comes up now. He does it before she gets there, and he has stopped saying it is so they can spread the stacks out, and neither of them has said anything about that either.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Shut the stair door. It does not shut. Push it to anyway.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.base">>
<<script>>setup.markCanvasTriggered("hub_sabin");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.base") === -1) { vn.push("hub_sabin.base"); }<</script>>
<<nobr>>
<<link "Ask him what it means." "Canvas_hub_sabin_Node_ask">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 4}]})>>
<span @class="setup.isChoiceVisited('hub_sabin:cc0') ? '' : 'unlocked-choice'">
<<link "Stay while the floor empties." "Canvas_hub_sabin_Node_late">><<script>>setup.markChoiceVisited("hub_sabin:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 7}]})>>
<span @class="setup.isChoiceVisited('hub_sabin:cc1') ? '' : 'unlocked-choice'">
<<link "Reach across the bench for it." "Canvas_hub_sabin_Node_tease">><<script>>setup.markChoiceVisited("hub_sabin:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 10}]})>>
<span @class="setup.isChoiceVisited('hub_sabin:cc2') ? '' : 'unlocked-choice'">
<<link "Take the page round with the blouse open." "Canvas_hub_sabin_Node_flash">><<script>>setup.markChoiceVisited("hub_sabin:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 14}]})>>
<span @class="setup.isChoiceVisited('hub_sabin:cc3') ? '' : 'unlocked-choice'">
<<link "Kiss him at the bench." "Canvas_hub_sabin_Node_kiss">><<script>>setup.markChoiceVisited("hub_sabin:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "relation", "operator": "gte", "value": 18}, {"type": "flag", "subject": "player", "flag_key": "sabin_opened_up", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_sabin:cc4') ? '' : 'unlocked-choice'">
<<link "Let him have you over the bench." "Canvas_hub_sabin_Node_bench">><<script>>setup.markChoiceVisited("hub_sabin:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "sabin_opened_up", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_sabin:cc5') ? '' : 'unlocked-choice'">
<<link "Clear the bench." "Canvas_loop_sabin_lab_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_sabin:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Back down to the floor." "Location_the_rise_floor">><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>She asks him what a thing means and he is off. The mug goes down for it. Nobody has asked this man anything in four months that was not about a roster or a budget, and it shows in under a sentence.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> It means they were growing the substrate and the memory scaffold in the same run and writing it up as one process. Which it is not. Which is why everything after page nine of that file is nonsense.</div></div><p>He draws it on the back of a delivery note, badly, talking the whole way through, and then draws it again when the first one goes wrong. It takes an hour. She has not had to ask a second question.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Do not let me do that again. I will do that again.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He is going to be easy. Everybody easy she has ever met was also stupid, and she keeps waiting for the second half of that to turn up.</div></div>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.ask">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.ask") === -1) { vn.push("hub_sabin.ask"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "add", 2.0, true, null);setup.showEffectNotification();<</script>>
[[Leave it there.->Location_sabin_lab]]<img src="./videos/scenes/sabin_after_eight.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Eight o'clock and the level below empties in about four minutes. Chairs, lift, lift, lift, and then nothing. After that the building has two people in it and one of them does not know he is being counted.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> They all go at once. Every night, the same four minutes. I have never worked out whether somebody says something or they just all know.</div></div><p>Sound does something odd up here once the floor is empty. No partitions, no carpet, a ceiling that goes straight up into the vents. A chair leg on concrete arrives twice. Once off the glass, a half-beat behind.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Do not drop anything. I put a tray down too hard in March and heard it come back at me out of the stairwell like somebody else had dropped it.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Two people in a building this size is not privacy. It is the opposite of privacy, with nobody in it to want anything.</div></div>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.late">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.late") === -1) { vn.push("hub_sabin.late"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "add", 3.0, true, null);setup.showEffectNotification();<</script>>
[[Leave it there.->Location_sabin_lab]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_sabin_tease_t2"] to ($game_state.media_cycle["scenes_rung_sabin_tease_t2"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_sabin_tease_t2"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_sabin_tease_t2"]>><<if _mc is 0>><video src="./videos/scenes/rung_sabin_tease_t2/c3b2dcfe70e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_sabin_tease_t2/c6dce7d2644.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_sabin_tease_t2/c249a627355.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_sabin_tease_t2/cbad08ac5e1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He wants the box behind the box, the way he always does, and she goes across the bench for it instead of round. Two buttons were down before she came up the stairs. She takes her time getting there.</p><p>Glass on two sides, the lights on in here, and nothing but dark outside. The window hands him the whole front of her while he is looking straight down at a page, and he does not have to move his head to take it.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "corruption", "operator": "lt", "value": 4}]})>>
<p>He watches the reflection until she straightens up, and then he looks at the bench, and then he says it out loud, because he has never once in his life let a thing like that go unsaid.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> The window works both ways after dark. I am telling you because if I say nothing now I become a man who said nothing, and I would rather be the other kind.</div></div><p>He does not ask her to do up the buttons and he does not look at them again.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "corruption", "operator": "gte", "value": 4}]})>>
<p>He does not look at the bench this time. He holds the glass while she is bent across it, and when she straightens up and catches him in the reflection he stays exactly where he is.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> No. I was not checking a reading and I am not going to say I was. If you would rather I stopped, say so and I will stop. You are not saying so.</div></div><p>She does not say so. He turns back to the page and his hand stays where it stopped.</p>
<</if>><p>The box he sent her for is the one already open in front of him. Neither of them says anything about that, and the next thing he needs is off the same shelf.</p>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.tease">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.tease") === -1) { vn.push("hub_sabin.tease"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "add", 3.0, true, null);setup.applyAndNotifyTrait("npc", "npc_sabin", "corruption", "add", 2.0, true, null);setup.showEffectNotification();<</script>>
[[Leave it there.->Location_sabin_lab]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_sabin_flash_t3"] to ($game_state.media_cycle["scenes_rung_sabin_flash_t3"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_sabin_flash_t3"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_sabin_flash_t3"]>><<if _mc is 0>><video src="./videos/scenes/rung_sabin_flash_t3/c22eb28ff9d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_sabin_flash_t3/c364c1e7701.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_sabin_flash_t3/c18246466d6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_sabin_flash_t3/cb03ccebac1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She opens the blouse on the stairs and comes round to his side to put the page down. No window this time. He looks up, and looking up puts her tits at his eye level, nipples out, the near breast close enough to his mouth that he stops moving.</p><p>She keeps one hand flat on the page so it stays where she put it, and stays where she is with her tits over the top of it, one breast resting on his knuckles, nipples tight in the cold coming off the glass.</p><p>It is a page he has read before and it takes him a long time.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "corruption", "operator": "lt", "value": 4}]})>>
<p>He gets through the same four lines three times and then gives up on them out loud, which is the only way this man has ever given up on anything.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> I have lost my thread. That is not the page's fault. I am going to sit here and be embarrassed for a moment and then I am going to ask you to hand me the next one anyway.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_sabin", "trait_key": "corruption", "operator": "gte", "value": 4}]})>>
<p>He does not pretend to read it. He turns the page face down on the bench and looks at her from the stool, unhurried, taking as long over it as she took getting there.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> You have been doing this for a fortnight and I have known for a fortnight. Tell me to stop looking and I will. I have noticed you keep not telling me.</div></div>
<</if>><p>She hands him the next one. He asks for the one after that without looking down at the bench, and he gets through none of it.</p>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.flash">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.flash") === -1) { vn.push("hub_sabin.flash"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "add", 4.0, true, null);setup.applyAndNotifyTrait("npc", "npc_sabin", "corruption", "add", 2.0, true, null);setup.showEffectNotification();<</script>>
[[Leave it there.->Location_sabin_lab]]<video src="./videos/scenes/sabin_kiss_t4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She does it at twenty past nine, between one stack and the next, while he is still mid-sentence about a numbering system. Hand flat on his chest, two steps forward until the bench stops him, and her mouth on his.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> ...ah. Right. Yes.</div></div><p>He is careful about it for perhaps four seconds and then he is not careful at all. One hand in her hair, the other one back on the bench taking his weight, and the numbering system does not come up again.</p><p>She keeps her eyes open for some of it. His are shut the whole way through. That is the entire difference between what the two of them are doing and neither of them is ever going to say so.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> I am going to be extremely sensible about this in the morning, and I would like it on the record that I already know that now.</div></div>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.kiss">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.kiss") === -1) { vn.push("hub_sabin.kiss"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "add", 4.0, true, null);setup.showEffectNotification();<</script>>
[[Leave it there.->Location_sabin_lab]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_sabin_bench_t5"] to ($game_state.media_cycle["sex_sabin_bench_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_sabin_bench_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_sabin_bench_t5"]>><<if _mc is 0>><video src="./videos/sex/sabin_bench_t5/c3de6c7141a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/sabin_bench_t5/c8eea5ae4e7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/sabin_bench_t5/c155ac49849.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/sabin_bench_t5/c9633b85d17.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He clears the last two stacks off the end of the bench with his forearm and does not put them anywhere. She is out of the skirt before he has turned round, and puts herself face down on the steel because it is quicker than being asked.</p><span id="cascade-b2-beat-0"><p>He gets her open with two fingers first, standing behind her with his other hand flat between her shoulder blades, and he is unhurried about it in a way that has nothing to do with being kind. She is wet inside a minute.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Quiet. I mean that. It all goes up out of here and there is a man on the desk downstairs.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Nod.">><p>He pushes into her in one long shove and holds there with his hips against her ass, all the way in, her weight on her forearms. She does not make a sound. Her mouth is open against the steel and nothing comes out of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> There. God. Do not move for a second.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Let him move.">><p>Then he fucks her properly, one hand on the back of her neck holding her down on the bench, and every stroke of it goes through the steel and up into her arms. Her teeth stay shut on nothing at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Do not brace against it. Let it move you. There is nobody on this floor to see you do it.</div></div><span id="cascade-b2-beat-3"><<linkreplace "The lift.">><p>The lift moves somewhere below them and they both stop dead. Him buried in her to the root, her hand gone flat on the bench. They stay stopped for the eleven seconds it takes to pass the floor and keep going.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Nobody comes up here. Nobody comes up here.</div></div><span id="cascade-b2-beat-4"><<linkreplace "So do not stop.">><p>He goes harder for it. One hand comes round and over her mouth without asking and she lets him keep it there, breathing through her nose while he works, and the wet of her cunt is the loudest thing on the level.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Through your nose. That is it. I have got you.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Let him finish.">><p>He comes inside her with his hand still over her mouth and his forehead down between her shoulder blades, and the only sound in the whole building is him breathing out through his teeth.</p><span id="cascade-b2-beat-6"><<linkreplace "Get up off the bench.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He knows where every sample in this building is kept and he has never once had to think about it. That is what she came up four floors for and it is still four floors away.</div></div><p>He apologises to the two stacks he knocked on the floor, out loud, while he is doing his belt.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Sorry. Not to you. To those. Right. Middle hand tomorrow, or the late one? Which would you rather have. I am asking you, not telling you.</div></div>[[Leave it there.->Location_sabin_lab]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "hub_sabin">>
<<set $game_state.current_node = "hub_sabin.bench">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sabin.bench") === -1) { vn.push("hub_sabin.bench"); }<</script>>
<<script>>advanceTime(90);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_sabin", "relation", "add", 4.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "sabin_opened_up", "set");<</script>><img src="./videos/scenes/sabin_consults.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He comes down the row at ten past nine with a hand of printout and puts it on the corner of her desk. He does not sit down. There is nowhere on this floor for a second person to sit.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Nineteen months of this is in three different hands and not one of them agrees about what a batch is. I have to pick one of them and rebuild the other two onto it. Which one would you pick?</div></div><p>Then he stops. Mug halfway up, weight on one leg, looking at her the way people look at somebody they have asked something.</p><span id="cascade-b2-beat-1"><<linkreplace "Wait for the rest of it.">><p>She waits for the rest of it. There is no rest of it. The question has finished and he is still standing there, and the twenty other readers on this floor keep not talking, and the vents hums.</p><span id="cascade-b2-beat-2"><<linkreplace "Answer him.">><p>Four seconds. She has had the answer since the second column and she spends four of them not saying it, because a pause is a thing people notice and she does not know yet what this one buys.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The middle hand. It is the only one that puts a date on the same line as a quantity, so everything else can be hung off it. The other two you would be guessing at, and you would not know which parts.</div></div><span id="cascade-b2-beat-3"><<linkreplace "See what he does with that.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Yes. That is the one I would pick as well, and it has taken me three weeks to decide it. Right.</div></div><p>And then he moves on from it, the way a man moves on from a thing that is settled now, and it has cost him nothing at all to have asked her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> You are wasted on this floor. Come up after eleven — fourth level, the one with nothing on it. Bring the middle hand. I will find somebody else for the chair.</div></div><span id="cascade-b2-beat-4"><<linkreplace "That is that.">><p>He is gone back up the row before she has the printout square. The reader two desks along looks at her for slightly longer than is polite and then goes back to her screen.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Four seconds. She should not have needed four seconds, and she is going to be counting them for the rest of the afternoon.</div></div>[[Fourth level, then.->Location_the_rise_floor]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_sabin_consults">>
<<set $game_state.current_node = "cap_sabin_consults.base">>
<<script>>setup.markCanvasTriggered("cap_sabin_consults");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_sabin_consults.base") === -1) { vn.push("cap_sabin_consults.base"); }<</script>>
<<script>>advanceTime(20);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "sabin_consulted", "set");<</script>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "sabin_met", "operator": "is_false"}]})>>
<p>Her own clothes and a reader's card in her pocket, and the two do not go together well enough for the man at the desk to finish the sentence he starts. The kit is in the bag. The kit being in the bag is the whole problem with the kit.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "sabin_met", "operator": "is_true"}]})>>
<p>Two readers look up at somebody they do not recognise standing at the end of the row, and one of them starts getting out of her chair to be helpful. She is back at the lift before anybody has to decide anything.</p>
<</if>>
<<set $game_state.current_canvas = "react_rise_stranded">>
<<set $game_state.current_node = "react_rise_stranded.base">>
<<script>>setup.markCanvasTriggered("react_rise_stranded");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_rise_stranded.base") === -1) { vn.push("react_rise_stranded.base"); }<</script>>
<<script>>advanceTime(10);<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("cover_research");setup.showEffectNotification();<</script>>
[[Back down.->Location_the_waterfront]]<p>She gets as far as the desk. The man behind it looks up at her own clothes, asks politely who she is here to see, and there is no answer to that which does not end with somebody writing something down.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A reader turns up looking like a reader and carrying paper that says so. She has neither, and both are sold at the same end of the same row.</div></div>
<<set $game_state.current_canvas = "react_rise_no_kit">>
<<set $game_state.current_node = "react_rise_no_kit.base">>
<<script>>setup.markCanvasTriggered("react_rise_no_kit");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_rise_no_kit.base") === -1) { vn.push("react_rise_no_kit.base"); }<</script>>
<<script>>advanceTime(10);<</script>>
[[Back down.->Location_the_waterfront]]<img src="./videos/scenes/sabin_hires.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The man who comes down to meet her is forty-ish, in a shirt worth more than her month, with a mug in one hand and a printed page in the other and still reading the page. He gives his name as Sabin, once, the way people do who expect to be working with you.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Do not tell me about yourself. Everybody tells me about themselves, it takes twenty minutes, and it has never once been true. Tell me what this says.</div></div><p>He puts the page into her hand. A procurement log, four columns, two of them in a hand that gave up on legibility around its second year. Then he goes back to the mug and waits.</p><span id="cascade-b2-beat-1"><<linkreplace "Read it.">><p>She has it in about nine seconds and holds the answer for another four, because nine seconds is a thing worth being careful about in front of a stranger.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It is a consumables order. Somebody has been buying roughly twice what the run needs and signing for all of it, every month, for a year.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Good. That is what it says.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Wait for the questions.">><p>She waits for the part where he looks at the card in the sleeve. He turns it over once without reading it and puts it face down on the desk next to the mug.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Two years somewhere. Everybody has two years somewhere. I am four months into eleven years of a dead man's filing, I need people who can read, and there is nobody in this city checking anybody's paper this month, myself included.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Terms, then.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Eight until noon or noon until eight, your choice, on the floor with the others. You do not come up to the lab. You do not sign anything out of the dry store. Fifteen a day. That is not generous, and which is what the budget says rather than what I think.</div></div><p>He says all of it to the page, and hands it back, and is already turning for the stairs by the end of the sentence.</p><span id="cascade-b2-beat-4"><<linkreplace "That is it.">><p>That is the whole interview. Six minutes, one page, and a man who has not looked at her face for longer than it takes to check that she is listening to him.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He has just told her where the other two rooms are and that she is not to go into them, and it has not crossed his mind that this is information.</div></div>[[Start in the morning.->Location_the_rise_floor]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_sabin_hires">>
<<set $game_state.current_node = "cap_sabin_hires.base">>
<<script>>setup.markCanvasTriggered("cap_sabin_hires");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_sabin_hires.base") === -1) { vn.push("cap_sabin_hires.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "sabin_met", "set");<</script>><p>The frame takes her standing, arms out where the arms go, and the mirror bolted at head height puts her own hands in front of her.</p><span id="cascade-b1-beat-0"><p>He works behind her and she can watch every part of it in the glass.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> The glass is not there to be kind to you. It is there so a man working on himself can see what his own hands are doing, and until today I have never had anybody else to stand in it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Do not hold still on my account. Nothing I am doing needs you still.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Watch him work.">><p>He is fast. Nine years of doing this to himself, in this frame, in this room, with these hands, and he does it to her at the speed of a man who stopped needing to think about the order of it a long time ago.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> It is not surgery. It is a slot and a seat. The hard part was done nine years ago by somebody else and it was not done to be undone.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Let him seat it.">><p>Something goes home at the back of her skull with a pressure and no sound at all. Not a click. Less than a click. The sort of small mechanical fact a body is never told about.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Seated. That is the whole of the mechanical part of it and it is done.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Wait for it.">><p>She waits. She is aware of waiting, and of the shape of the thing she is waiting for, and of the mirror in front of her with her own hands in it not doing anything at all.</p><p>Nothing arrives. No room, no smell, no name, no afternoon. The inside of her head is exactly as furnished as it was this morning and it is furnished the same way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Well.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Tell him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Nothing.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> No.</div></div><p>That is the whole of what he says about it. He is not surprised and he is not disappointed and he does not offer her a reason, and he starts putting the tools back where the tools live.</p><span id="cascade-b1-beat-5"><<linkreplace "Ask whether it is supposed to.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Is it supposed to do something.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> It is supposed to be in there. It is in there.</div></div><p>Which is true, and answers nothing, and is said in the voice of a man who has already worked out the part he is not going to say to her today.</p><span id="cascade-b1-beat-6"><<linkreplace "Get out of the frame.">><p>He gets her out of the cradles and hands her the coat off the end of the bench, and the pocket she has been keeping her hand over for a week is flat and empty for the first time since the Reach.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A week of afternoons on that bench, and it went in like a fuse. She cannot even manage to feel cheated about it.</div></div>[[Out.->Location_underworld_strip]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_install_one">>
<<set $game_state.current_node = "cap_install_one.base">>
<<script>>setup.markCanvasTriggered("cap_install_one");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_install_one.base") === -1) { vn.push("cap_install_one.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "pieces_seated", "add", 1.0, false, null);setup.showEffectNotification();<</script>><p>He is there when she gets back. Standing this time, coat still on, over by the feed line. She notices on the way in that she has stopped being surprised by it, and does not say anything about that either.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Kess's latch.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Still on. It has never been the latch.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Wait for him to say it.">><p>The thing out of Grier's drawer is in her coat pocket and has been in her coat pocket since the Reach. She has not put it down on a surface once, in any room, including this one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> You have it on you. You have had it on you the whole way here and every day before that, which tells me more than you asking me questions ever has.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Get your coat.">><p>He holds the door the way he held it last time and does not say where, because they both already know where, and she goes out past him with her hand still flat over the pocket.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Head down for the middle of it. Same as before, and you liked it no better the first time.</div></div>[[Go with him.->Location_cain_lab]]
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cain_comes_again">>
<<set $game_state.current_node = "cain_comes_again.base">>
<<script>>setup.markCanvasTriggered("cain_comes_again");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cain_comes_again.base") === -1) { vn.push("cain_comes_again.base"); }<</script>>
<<script>>advanceTime(45);<</script>><img src="./videos/scenes/grier_drawer.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She does her coat up and tells him to give her the one he kept. Not a question. Not what it is, not how he came by it, and no account of how she knows. Just give it to her.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years. Nobody has ever come into this room and said that to me.</div></div><p>He does not ask her how she knows. He goes to the bench and stands over the drawer under it with his back to her a while, and what takes him the time is not deciding. It is shifting nine years of junk off the top of it.</p><span id="cascade-b2-beat-1"><<linkreplace "Let him talk.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years this has sat in with the fuses. I could not tell you what it does. It does not read on anything I own and I gave up trying somewhere around the second year, and I have not had it out since.</div></div><p>He puts it into her hand with no ceremony whatever. Smaller than a coin, dull, not a mark on it anywhere, and it does not look like anything at all.</p><span id="cascade-b2-beat-2"><<linkreplace "Close your hand on it.">><p>It weighs nothing. It is exactly the temperature of the room. She is holding nine years of somebody in her palm and the somebody is her, and her hand does not shake, because her hands do not.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Do not tell me what it is. I have had a very long nine years off not knowing and I have decided I would like to keep them.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Ask him one more thing.">><p>He is spent and he has nothing left to hold over her, and that is the only reason the next question gets an answer. She asks where the work happens now. Where a person would go, if the study never stopped.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> It never stopped. First thing I ever said to you. There is a half-built tower going up on the edge of this district — Vance money, twenty floors, eight of them with lights in and the rest bare concrete.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Get the name.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> The Rise, they are calling it. You can see it from the top of the lane on a clear day, going up beside the big one. They are taking readers on off the street and checking nothing, because whoever is up there wants it finished this year.</div></div><p>He goes back to the chair. The bottle is where the bottle always is, the drawer is standing open and empty behind him, and he does not look at it once on the way past.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A tower on the edge of his own district, hiring anybody who can read. That is where the second one is. She is going to need papers that say she can.</div></div>[[Down the lane.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_grier_gives">>
<<set $game_state.current_node = "cap_grier_gives.base">>
<<script>>setup.markCanvasTriggered("cap_grier_gives");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_grier_gives.base") === -1) { vn.push("cap_grier_gives.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "piece_one_held", "set");setup.applyAndNotifyFlag("player", null, "rise_named", "set");<</script>><p>What comes down her arm is not routes and drops the way a courier comes apart. It is one room, kept for nine years the way a man keeps a thing he has decided was somebody else's fault, and she is standing in it.</p><span id="cascade-b1-beat-0"><p>A theatre with the lights down at the edges. A body on the table with the back of its head open and its face turned away, because the man whose eyes she is borrowing never once looked at the face.</p><p>Company work, unhurried, four people at it and none of them hurrying. Somebody in the corner is eating.</p><span id="cascade-b1-beat-1"><<linkreplace "Look at the trays.">><p>Three shallow trays on a stand at the head of the table, and a man dividing what came out of the head between them, taking his time over it, because the whole point of the exercise is that no two of them may ever sit together again.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Three. By kind. Exactly what Cain said. Here it is being done, and not one person in that room thinks they are doing anything unusual.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Find him in it.">><p>Grier is at the end of the bench with his hands full of tools nobody is asking him for. Nobody speaks to him all night. He is the one they would not miss for an hour. That is the whole of why it worked.</p><p>There is a second man out in the corridor, standing in the doorway light, waiting. She does not get a face. Grier has two trays in his arms by then and he never once looks up.</p><span id="cascade-b1-beat-3"><<linkreplace "Watch him take it.">><p>He takes the one he came for and the one sitting next to it, because two is not meaningfully harder to carry than one and he has already worked out he is never coming back through that door.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He was not stealing from her. He did not know there was a her to steal from. She was the tray on the left.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Come out of it.">><p>It lets go of her all at once and she is on the bench again with her cheek on the wood and his weight coming off her back, and he is saying something sour about the state of his knees.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> You have gone quiet. Which is an improvement, if I am honest with you, and I generally am.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He still has it. It has been in this room the entire time she has been coming here, and he does not know what it is.</div></div>[[Ask him for it.->Location_grier_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "grier_drain_canvas">>
<<set $game_state.current_node = "grier_drain_canvas.d0">>
<<script>>setup.markCanvasTriggered("grier_drain_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("grier_drain_canvas.d0") === -1) { vn.push("grier_drain_canvas.d0"); }<</script>><p>The drain fires the way it fires now, with nothing left in it to find. Just his charge coming loose down her arm and the afternoon going soft behind his eyes. He will wake up in that chair sour and none the wiser.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> ...Mm. Pull the door to on your way.</div></div>
<<set $game_state.current_canvas = "grier_drain_canvas">>
<<set $game_state.current_node = "grier_drain_canvas.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("grier_drain_canvas.done") === -1) { vn.push("grier_drain_canvas.done"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave him to it.->Location_the_waterfront]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_finish_facial_t5"] to ($game_state.media_cycle["sex_grier_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/grier_finish_facial_t5/c2cf9a3c1f1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_finish_facial_t5/c7e15465cc1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_finish_facial_t5/c8c85e60499.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_finish_facial_t5/cccf5118cf5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes on her face with his fist shut in her hair and the glass finally down, and looks at what he has put there for a long moment without saying anything. Nothing comes loose but him. The drain only opens the one way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> There. Do not wipe that on my chair. There is a rag on the bench and it is cleaner than anything else in here, which ought to tell you what sort of a place you have been walking to.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_finish_inside_t5"] to ($game_state.media_cycle["sex_grier_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/grier_finish_inside_t5/c3af08e4a8d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_finish_inside_t5/c9f9c724d8b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_finish_inside_t5/c7910162eb3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_finish_inside_t5/cb1514c19e0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes in her cunt on the bench and holds her hips down against the wood until it has stopped, then steps back breathing like a man who has carried something up a flight of stairs. She has taken nothing. Not this way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Right. Off the bench. I have a bottle to get back to and you have a walk, and neither of us is going to stand here pretending that was anything other than exactly what it was.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_finish_anal_t5"] to ($game_state.media_cycle["sex_grier_finish_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_finish_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_finish_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/grier_finish_anal_t5/c3d82c4c4c4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_finish_anal_t5/c3e3f9ac87f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_finish_anal_t5/c196ddea8e7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_finish_anal_t5/c5535e12bc3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes in her ass and the drain opens under it the way it is built to. The shudder cracking him wide, her hand still shut on his wrist, nine years of him starting to come loose down her arm.</p>
<</if>>
<<set $game_state.current_canvas = "loop_grier_finisher">>
<<set $game_state.current_node = "loop_grier_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_grier_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_grier_finisher.climax") === -1) { vn.push("loop_grier_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_grier_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Get your coat." "Location_the_waterfront">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_finisher:cc0");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_grier_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Let it go — wrong gear." "Location_the_waterfront">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_finisher:cc1");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_grier_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Let it go — the drain is empty. Take a night on the feed line at the berth and it reloads." "Location_the_waterfront">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_finisher:cc2");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "grier_drains_done", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_grier_finisher:cc3') ? '' : 'unlocked-choice'">
<<link "Take what he carries." "Canvas_grier_drain_canvas_Node_d0">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "grier_drains_done", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_finisher:cc3");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "grier_drains_done", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_grier_finisher:cc4') ? '' : 'unlocked-choice'">
<<link "Drink him down again." "Canvas_grier_drain_canvas_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_finisher:cc4");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "grier_drains_done", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "grier_drains_done", "operator": "gte", "value": 1}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_grier_finisher = [{"text": "Get your coat.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Let it go \u2014 wrong gear.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]}}, {"text": "Let it go \u2014 the drain is empty. Take a night on the feed line at the berth and it reloads.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]}}, {"text": "Take what he carries.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "grier_drains_done", "operator": "lt", "value": 1}]}}, {"text": "Drink him down again.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "grier_drains_done", "operator": "gte", "value": 1}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_grier_finisher",
choices: window._engineNoExitsDiag_loop_grier_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_grier_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_grier_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_loop_t4"] to ($game_state.media_cycle["sex_grier_loop_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_loop_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_loop_t4"]>><<if _mc is 0>><video src="./videos/sex/grier_loop_t4/c02c0d71e77.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_loop_t4/c7a2be8e0bf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_loop_t4/c578f2f44ac.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_loop_t4/cdee0f025f6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He does not get up. She takes her coat off and then the rest of it and folds all of it onto the arm of the chair, because there is nowhere else in this room she would put anything of hers down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> All of it. I want the whole build, not the parts you have decided I am getting. You are not doing me a favour and I would rather you stopped standing like you were.</div></div><p>He watches her strip the way he watched her under the bulb, takes another mouthful, and does not put a hand on himself once.</p>
<<set $game_state.current_canvas = "loop_grier_room">>
<<set $game_state.current_node = "loop_grier_room.intro">>
<<script>>setup.markCanvasTriggered("loop_grier_room");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_grier_room.intro") === -1) { vn.push("loop_grier_room.intro"); }<</script>>
<<nobr>>
<<link "Get down in front of him." "Canvas_loop_grier_room_Node_base_oral_grier">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_loop_oral_t5"] to ($game_state.media_cycle["sex_grier_loop_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_loop_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_loop_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/grier_loop_oral_t5/c2bf86480e9.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_loop_oral_t5/c5e34c5d737.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_loop_oral_t5/c05992dd97c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_loop_oral_t5/cc470d47829.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees on the boards with his cock in her mouth and the glass still in his hand above her. He drinks over the top of her head while she works, and the only sound in the room is her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Not with your hand. I did not ask for your hand. Your mouth, and take your time over it. I am not going anywhere and neither, apparently, are you.</div></div>
<<set $game_state.current_canvas = "loop_grier_room">>
<<set $game_state.current_node = "loop_grier_room.base_oral_grier">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_grier_room.base_oral_grier") === -1) { vn.push("loop_grier_room.base_oral_grier"); }<</script>>
<<nobr>>
<<link "Keep him in your mouth." "Canvas_loop_grier_room_Node_base_oral_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Get up on the bench." "Canvas_loop_grier_room_Node_base_vaginal_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_grier_room:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_grier_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_room:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_loop_vaginal_t5"] to ($game_state.media_cycle["sex_grier_loop_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_loop_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_loop_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/grier_loop_vaginal_t5/c095db14345.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_loop_vaginal_t5/c511a71a919.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_loop_vaginal_t5/c800d6cc4bc.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_loop_vaginal_t5/cd7225570cd.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She gets up onto the bench he has not worked at in nine years, and he stands in between her knees and puts his cock in her cunt there, both hands flat on the wood either side of her hips.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years that bench has had nothing on it worth the dust. Look at what is on it now. Lie back properly. I want the whole of you on there.</div></div>
<<set $game_state.current_canvas = "loop_grier_room">>
<<set $game_state.current_node = "loop_grier_room.base_vaginal_grier">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_grier_room.base_vaginal_grier") === -1) { vn.push("loop_grier_room.base_vaginal_grier"); }<</script>>
<<nobr>>
<<link "Let him have it." "Canvas_loop_grier_room_Node_base_vaginal_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_loop_grier_room_Node_base_oral_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn over — give him your ass." "Canvas_loop_grier_room_Node_base_anal_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_grier_room:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_grier_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_room:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_loop_anal_t5"] to ($game_state.media_cycle["sex_grier_loop_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_loop_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_loop_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/grier_loop_anal_t5/c2a10f2232b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_loop_anal_t5/c90c938052a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_loop_anal_t5/c3437092145.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_loop_anal_t5/ce6e0d2a6a9.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Face down on the bench with her ass up and his cock working into it, one of his hands spread between her shoulder blades to keep her flat exactly where he put her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Flat. Stay flat. That is what a bench is for and it is what you are for this afternoon, and if you want to make a noise about it you can make it into the wood.</div></div><p>She gets a hand back and closes it around his wrist, skin on skin, and holds it there. That is the seat. The drain sits in the contact and waits for a shudder that mostly does not come.</p>
<<set $game_state.current_canvas = "loop_grier_room">>
<<set $game_state.current_node = "loop_grier_room.base_anal_grier">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_grier_room.base_anal_grier") === -1) { vn.push("loop_grier_room.base_anal_grier"); }<</script>>
<<nobr>>
<<link "Take it." "Canvas_loop_grier_room_Node_base_anal_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on him." "Canvas_loop_grier_room_Node_base_vaginal_grier">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_grier_room:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — and take what he carries." "Canvas_loop_grier_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_grier_room:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "npc_at_location", "location_id": "grier_room", "npc_id": "npc_grier", "operator": "is_present"}]})>>
<p>He does not look up when she goes. Three glasses down and talking to the room about a tolerance, and the side door is where she left it, hanging open on a lockup with nothing in it worth taking.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "npc_at_location", "location_id": "grier_room", "npc_id": "npc_grier", "operator": "is_absent"}]})>>
<p>The chair is empty and the ring is cold and the bottle is where he left it. Wherever a man like that goes after midnight, it is not far and it is not interesting.</p>
<</if>>
<<set $game_state.current_canvas = "grier_room_offhours">>
<<set $game_state.current_node = "grier_room_offhours.base">>
<<script>>setup.markCanvasTriggered("grier_room_offhours");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("grier_room_offhours.base") === -1) { vn.push("grier_room_offhours.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Back down the lane.->Location_the_waterfront]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "lt", "value": 4}]})>>
<p>He does not tell her to get out again. He does not ask her to sit down either. She comes in, and he keeps drinking, and the afternoon goes past at the pace of a man who has nowhere to be in it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Door was open. Door is always open. Nothing in here worth the walk, which you will work out on your own eventually.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "gte", "value": 4}, {"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "lt", "value": 10}]})>>
<p>She has been in that chair enough times now that he stops watching the door when it opens. He does not say hello. He pours, and he looks at her over the top of it for longer than he used to.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years I have not had one of you in a room. Forgot how still you sit. Nothing on you moves unless you decide it moves. Bring the bottle over here when you pour it. I am not getting up for it and you are already halfway across.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "gte", "value": 10}, {"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "lt", "value": 14}]})>>
<p>He has stopped pouring by the time she is through the door. The bottle stays on the arm of the chair and he sits forward with his forearms on his knees, looking at her the way a job comes up the bench.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> You keep coming back to a man with nothing. You want something, you are not getting it, and you keep coming back anyway. I have decided I do not care why. Pour mine and put the cap back on yours. You never drink it and I have stopped pretending I have not noticed.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "gte", "value": 14}]})>>
<p>He does not get up any more and he does not ask her anything. The chair is where he wants her and they both know it, and the only thing he says when she comes through the door is what he wants doing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Coat.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.base">>
<<script>>setup.markCanvasTriggered("hub_grier");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.base") === -1) { vn.push("hub_grier.base"); }<</script>>
<<nobr>>
<<link "Sit with him a while." "Canvas_hub_grier_Node_sit">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bottle_held", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "grier_opened_up", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc0') ? '' : 'unlocked-choice'">
<<link "Drink with him." "Canvas_hub_grier_Node_drink">><<script>>setup.markChoiceVisited("hub_grier:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="He pours his own. The Anchor keeps the bottom shelf at twenty coin a bottle, two streets off the water, and it is on the way down the lane.">He pours his own. The Anchor keeps the bottom shelf at twenty coin a bottle, two streets off the water, and it is on the way down the lane.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bottle_held", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "grier_opened_up", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc1') ? '' : 'unlocked-choice'">
<<link "Drink with him. (He talks when he is this far down.)" "Canvas_hub_grier_Node_drink_after">><<script>>setup.markChoiceVisited("hub_grier:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "gte", "value": 14}, {"type": "flag", "subject": "player", "flag_key": "grier_opened_up", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc2') ? '' : 'unlocked-choice'">
<<link "Get down in front of him." "Canvas_hub_grier_Node_knees">><<script>>setup.markChoiceVisited("hub_grier:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "grier_opened_up", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc3') ? '' : 'unlocked-choice'">
<<link "Let him have the rest of it." "Canvas_loop_grier_room_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_grier:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "cain_absent_confirmed", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "third_located", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc4') ? '' : 'unlocked-choice'">
<<link "Ask him about Cain." "Canvas_hub_grier_Node_the_third">><<script>>setup.markChoiceVisited("hub_grier:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Step away." "Location_grier_room">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She takes the other chair, which has a coat on it and has had a coat on it for a long time, and she moves the coat and sits down and does not say anything at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> You are still here.</div></div><p>It is not a question and she does not answer it, and after a while he pours another one and does not offer her any, and that is the whole of the hour.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> If you are going to keep sitting in that chair you can start bringing something with you. I am not pouring for two off my own shelf. There is a bar on the water that will rob you of twenty for it, and you will pay it, and we both know that.</div></div>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.sit">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.sit") === -1) { vn.push("hub_grier.sit"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "add", 2.0, true, null);setup.showEffectNotification();<</script>>
[[Go.->Location_the_waterfront]]<img src="./videos/scenes/grier_drink.png" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She puts the bottle on the arm of the chair where his glass lives. He reads the label the way he reads everything, front and back, and puts it down again without saying one word about it.</p><p>Then he pours two. Hers goes on the boards by her foot and stays there, because whatever they put in her does not take drink. He clocked that on the first bottle and has not mentioned it since.</p><p>Three glasses in he starts talking and all of it is bench work. Tolerances. A jig he built for a man who never paid him. There is an hour of him in that chair and she can spend it however she likes.</p>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.drink">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.drink") === -1) { vn.push("hub_grier.drink"); }<</script>>
<<nobr>>
<<link "Just drink, and let him talk." "Canvas_hub_grier_Node_drink_plain">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "gte", "value": 4}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc5') ? '' : 'unlocked-choice'">
<<link "Keep bending down for your glass." "Canvas_hub_grier_Node_drink_tease">><<script>>setup.markChoiceVisited("hub_grier:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="He is still watching the door more than he is watching her. She could bend double in that chair tonight and he would not look up off the bottle.">He is still watching the door more than he is watching her. She could bend double in that chair tonight and he would not look up off the bottle.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_grier", "trait_key": "relation", "operator": "gte", "value": 10}]})>>
<span @class="setup.isChoiceVisited('hub_grier:cc6') ? '' : 'unlocked-choice'">
<<link "Open the blouse when you pour." "Canvas_hub_grier_Node_drink_flash">><<script>>setup.markChoiceVisited("hub_grier:cc6");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Not yet. He would say something about it and it would be the wrong something, and she would have spent the only thing she has on this man for a sentence.">Not yet. He would say something about it and it would be the wrong something, and she would have spent the only thing she has on this man for a sentence.</span><br>
<</if>>
<</nobr>><p>She lets it run and does not ask him a single question. That is the method and it is the only one that has ever worked on him. A question shuts his mouth. Silence keeps it open.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Everything gets stamped out now. Eleven thousand of a thing and not one of them touched by a hand. You would not know what I am on about, and that is restful, so I am going to keep going.</div></div>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.drink_plain">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.drink_plain") === -1) { vn.push("hub_grier.drink_plain"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "add", 2.0, true, null);setup.applyAndNotifyTrait("player", null, "bottle_held", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "grier_drank_with", "set");<</script>>
[[Let the hour go.->Location_grier_room]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_grier_tease_t2"] to ($game_state.media_cycle["scenes_rung_grier_tease_t2"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_grier_tease_t2"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_grier_tease_t2"]>><<if _mc is 0>><video src="./videos/scenes/rung_grier_tease_t2/c9d541f2870.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_grier_tease_t2/c241869e6d4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_grier_tease_t2/ce3dc2eca8b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_grier_tease_t2/cfc0e7f8f35.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Her glass has stood full on the boards by her foot since he poured it, and she goes down after it, slow, every time he gets near the end of a sentence. Two buttons are down. She did those before she sat.</p><p>From that chair he gets the whole way down the front of her every time, four seconds of it, and she is back up before either of them has to decide what it was.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Put that up on the arm where you can reach it. You are going up and down like a bloody bench press and I am losing my thread.</div></div><p>She leaves it where it is. He does not ask again and he does not go back for the thread, and the next time she goes down for the glass he stops talking altogether until she is back up.</p>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.drink_tease">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.drink_tease") === -1) { vn.push("hub_grier.drink_tease"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "add", 3.0, true, null);setup.applyAndNotifyTrait("player", null, "bottle_held", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "grier_drank_with", "set");<</script>>
[[Let the hour go.->Location_grier_room]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_grier_flash_t3"] to ($game_state.media_cycle["scenes_rung_grier_flash_t3"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_grier_flash_t3"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_grier_flash_t3"]>><<if _mc is 0>><video src="./videos/scenes/rung_grier_flash_t3/c0ade59da6d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_grier_flash_t3/c3b8b0de3c2.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_grier_flash_t3/cee231736f1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_grier_flash_t3/ceea89c4966.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She does not bother with the buttons. She has the blouse open before she lifts the bottle and pours it over the arm of his chair, tits out above the glass, nipples tight in the cold, the underside of one breast on the back of his hand.</p><p>She stays there while he drinks it. He does not look away and does not pretend to be doing anything else. He takes his time over her tits, the nipples first and then the seam under the left breast where the skin stops matching.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> You are doing that on purpose. Have been for weeks. I am not going to ask you to stop and you know I am not, so we can both leave it where it is.</div></div><p>Then he takes the glass off her and holds her there by the wrist, in the light, and turns her hand over and looks at it, and what comes out of him is not about any of what she was doing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Somebody put four hours into that jaw and about nine seconds into your wrists. You can see exactly where the money ran out on you. They rushed you out of the door and they charged the same for it.</div></div><p>He lets go and sits back and takes the talk wherever he wants it. Somewhere under all of it he says a thing about a bench nine years ago, and she keeps every word of it.</p>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.drink_flash">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.drink_flash") === -1) { vn.push("hub_grier.drink_flash"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "add", 4.0, true, null);setup.applyAndNotifyTrait("player", null, "bottle_held", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "grier_drank_with", "set");<</script>>
[[Let the hour go.->Location_grier_room]]<p>He is on the third before she has her coat off, and he does not read the label this time. The bottle from Tuesday is on the boards by the chair with about an inch left standing in the bottom of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Good. Sit. I have had a day, and the day had a man in it who wanted a thing dressing back by hand and then looked at my hands.</div></div><p>She pours for him and keeps pouring for him and he goes soft and slow and pleased about it, further under than she has ever taken him, and somewhere around the fifth one his sentences stop finishing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Eleven years I had my hands inside things like you. Every seam, every join, elbow deep in it. Never once thought about having one on that bench. Now I do, and this is what I get to do about it.</div></div><p>He says it to the middle of the room with the glass resting on his chest, and then he says the other half of it before she has worked out whether she is supposed to answer the first.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> And I did that to myself, before you say it. Nobody poured it down me. There is not a man alive I can send the bill to, though I have had nine years of working out where I would post it.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Twenty coin at the bar for an hour of a drunk man talking to the ceiling, and he has just told her more about himself than the whole ladder did.</div></div>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.drink_after">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.drink_after") === -1) { vn.push("hub_grier.drink_after"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "bottle_held", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Let the hour go.->Location_grier_room]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_grier_room_oral_t4"] to ($game_state.media_cycle["sex_grier_room_oral_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_grier_room_oral_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_grier_room_oral_t4"]>><<if _mc is 0>><video src="./videos/sex/grier_room_oral_t4/c8bab2e1538.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/grier_room_oral_t4/c78add5a2f3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/grier_room_oral_t4/c0521ec1329.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/grier_room_oral_t4/cf5c8702165.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He does not ask and she does not make him ask. She puts her coat over the arm of the chair, kneels down on the boards in front of him, and gets his belt open while he is still holding the glass.</p><span id="cascade-b2-beat-0"><p>His cock comes out half hard and stays half hard in her hand. Thick through the middle, heavy, the skin loose on it, warm the way a man is warm when he has sat still all day.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Do not look up at me like that. It has been a long time since that did anything on request and it is not going to start because you are pretty.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Put your mouth on it.">><p>She takes him into her mouth soft and works him that way, tongue flat under the head, her fist moving at the base to give him something to push into. He fills out a little and then stops.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Slower. Slower. You are working it like a pump handle. Whoever taught you that taught you to get a man out of a room, not to get him off.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Slower, then.">><p>She slows all the way down, takes him deep and holds there with her nose in the coarse grey hair at the base of him, swallowing around his cock until her eyes run, and comes off wet to the chin.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> That. That is nearly it. Do not stop doing that.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Keep going.">><p>She keeps at it until her jaw aches and the boards have printed her knees, and he gets hard, properly hard, and stays there for a while. His hand goes into her hair. His hips do not move at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Wait. Wait. No. No, it has gone. It is not going to come off a mouth, that is all that is.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Do not stop.">><p>He softens in her mouth across about a minute and she works him the whole minute anyway, harder, deeper, hand and mouth together, and none of it makes the slightest difference to him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Leave it. Leave it. You will have your jaw off and it will still be down there sulking, because that is not the end of me that answers any more and it has not been for years.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Get up off the floor.">><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "grier_drank_with", "operator": "is_false"}]})>>
<div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> It is not a mood and it is not her. Nine years of that bottle have taken the easy way out of him, and whatever he has in a drawer is behind whatever way is left.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "grier_drank_with", "operator": "is_true"}]})>>
<div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> It is not a mood and it is not her. Nine years of that bottle have taken the easy way out of him, and she has been walking the last month of it down the lane herself, twenty coin a time, out of money she earned on her back. Whatever he has in a drawer is behind whatever way is left.</div></div>
<</if>><p>She wipes her chin on the back of her wrist and finds her coat where she left it. Behind her the glass goes back down on the arm of the chair, exactly where it was when she came in.</p>[[Go.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.knees">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.knees") === -1) { vn.push("hub_grier.knees"); }<</script>>
<<script>>advanceTime(90);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "add", 4.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "grier_opened_up", "set");<</script>><p>She does not take her coat off. He notices that before she has got to the chair, and something in the set of him changes, because in four months she has never once come into this room and stayed dressed.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Tell me about Cain.</div></div><p>He puts the glass down on the arm of the chair. He does not pick it up again for a long time, which she has also never seen.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years, and you are the first person to walk in here and say that name at me. And you have said it like it is a thing a person is allowed to say.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Let him go.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> I had a trade. I had a bench with work on it and a name people said out loud when they wanted a thing dressed back by hand. He asked me for one night and by the Friday I had none of that and he had every single thing he came for.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> And he has not been down this lane since. Not once. Not to see whether the man who did it was still breathing.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Let him keep going.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> He was one of yours. Did he tell you that, or did he let you work it out? Before you. The run they failed on. They got him walking and got nothing else out of him, and everything since he has done to himself, in a room, with a mirror in it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> He is not a thing that was made properly. He is a thing they gave up on that would not lie down, and that is worse, and you can tell him I said so.</div></div><span id="cascade-b1-beat-3"><<linkreplace "And the trays.">><p>And then it comes out sideways, the way the useful things always come out of him. Not offered, spilled, in the middle of a sentence that was going somewhere else. She has already stood in that room and watched him do it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> There were three on that stand and I walked out with two of them, and I have never said that to a living soul, and I am saying it to you because you are the only one left it is any business of.</div></div><p>She does not move her face. There is one thing she could say that would stop him, and saying it means telling him what she does with her hand on a man's back, so she lets him have the whole of it instead.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> And I had two of them for about nine steps. The one I was sent for went out of my arms at the door into somebody else's, which was the arrangement. The one I kept was the one nobody had asked me for.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Ask about the third.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where did the third one go.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Up. A man came down for it in a case with a lock on it, did not speak to one person in that room, and took it up. That is the whole of what I saw and I saw it from the end of a bench with my arms full.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Ask him if he looked.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Four years I looked. Every road I put a hand on went up and stopped, and the two that did not stop, stopped me. It is up there. It has been up there since that night and whoever has it has had nine years to decide what it is for.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Nine years to decide what it is for, and no reason on earth to move first. He is not hiding it from her. He is holding it and waiting to see what walks in.</div></div><span id="cascade-b1-beat-6"><<linkreplace "Say nothing for a while.">><p>He picks the glass back up eventually and drinks and does not look at her, and the afternoon goes on the way afternoons go on in that room, with the tools still on the wall in their outlines.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Do not thank me for that. I did not do it for you and I would not do it again, and if you have got any sense you will stop asking about him in rooms he is not in.</div></div><span id="cascade-b1-beat-7"><<linkreplace "Work out what you have.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> One of them knows what is in that tray. The other one knows where the tray went. They have been forty minutes' walk apart for nine years and neither will ever put a foot in the other's room, and she is the only thing in this city that is welcome in both.</div></div>[[Go.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "hub_grier">>
<<set $game_state.current_node = "hub_grier.the_third">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_grier.the_third") === -1) { vn.push("hub_grier.the_third"); }<</script>>
<<script>>advanceTime(90);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_grier", "relation", "add", 2.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "third_located", "set");<</script>><img src="./videos/scenes/grier_first.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The side door gives on the back half of the lockup, and a man in a chair who does not get up. Sixty-odd, big hands gone loose in them, three days unshaved and most of a bottle down.</p><span id="cascade-b2-beat-0"><p>He looks at her for about two seconds. Not at the face. At her hands first, then her shoulders, then the way she is holding her own weight in the doorway.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> They are still making you, then.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Say nothing.">><p>He goes back to the drink. No threat in it, no fear in it, and no interest in her face at all. That is the one thing she came ready for and the one thing that does not happen.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A hundred and twenty coin of somebody else on her, and he did not get as far as it.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Ask him how.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> How.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Shoulders sit wrong on people. Yours sit exactly right, every time, and nobody's do. Had my hands inside enough of you to know the difference.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Let him talk.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Nine years since I touched one and I can still pick one out of a doorway. That is the whole of what I have got left, so you can see why I am not thrilled to see it walk in.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Ask what he did.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You built them.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> I handed tools to the men who built them. Different job. Worse one, if you want a view on it, and nobody ever has.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Push.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Did you ever keep anything.</div></div><p>The glass stops halfway up. He looks at her properly for the first time, and she has moved too fast, and she knows it a full second before he says anything at all.</p><span id="cascade-b2-beat-6"><<linkreplace "Wait for it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/grier.jpg" alt="Grier" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Grier</strong> Out.</div></div><p>She goes. The side door is not locked from the outside either, which she notices on the way through it, and it is the only thing the whole afternoon has given her.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He has it and he does not know he has it. Nothing to buy, nothing to trade, and no question that does not end at that door. Which leaves the long way.</div></div>[[Go back down the lane.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_grier_met">>
<<set $game_state.current_node = "cap_grier_met.base">>
<<script>>setup.markCanvasTriggered("cap_grier_met");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_grier_met.base") === -1) { vn.push("cap_grier_met.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "grier_met", "set");<</script>><img src="./videos/scenes/cain_lab_frame.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Twenty minutes with her head down again, and the two changes of direction again, and then the same door. He does not cover her eyes. He does not have to.</p><span id="cascade-b2-beat-0"><p>The paper is where it was. The benches are where they were. The frame stands open at the far end with the mirror bolted in at head height, and this time she walks the length of the room and looks into it.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What is this for.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Let him answer.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Me. I get into it, I open myself up, and I put in whatever I have got that is better than what is in me. Eleven years of that.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> The mirror is so I can watch my own hands. There has never been anybody else to do it.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Ask what she came to ask.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You used my name.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> It is your name.</div></div><p>Flat, the way he said it in the alley. Nothing on it, nothing offered with it, no weight he is asking her to take.</p><span id="cascade-b2-beat-3"><<linkreplace "Make him say the rest.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> You were a person. Not a machine that dreams it used to be one. They started with a living body and they built onto it, and the person was in there first.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Two.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> What is gone was taken. It was not damage, it was not a fault, and nothing broke. Somebody did it on purpose, with a plan and a schedule and a room booked for it.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Three.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> And they did not lift it out in one piece. They cut it into three by kind and they put the three in different places.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Why three.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> So that nobody could ever hold all of you at once. It worked.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Four.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I know where one of them is. A man in the Reach. He has had it nine years and he has never once known what it was.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Name.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Grier.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Ask the obvious thing.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You have known nine years. Go and take it off him.</div></div><p>He turns back to the bench and starts putting away things that are already away.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> You will do better out of him than I would.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Notice.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> That is not an answer. He has given her four tonight and that is not one of them.</div></div><span id="cascade-b2-beat-9"><<linkreplace "Refuse.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> No.</div></div><p>He stops with a spanner in his hand and waits. That is more room than anyone has given her to say a thing in.</p><span id="cascade-b2-beat-10"><<linkreplace "Say why.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I work. It is the only part of me that has ever been any use to anybody, and it works because there is nothing else in there. You want to put something else in there.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> If I get her back I stop being the thing that works. And then what am I. Somebody nobody has met, in a body the company owns, in a city holding my face on every camera at the curb.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Wait for the argument.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Yes.</div></div><p>He does not argue with any of it. He takes the grey coat off the chair and holds it out to her, and that is the whole of what he does about it.</p><p>She does not take the coat. She finds her own way to the door and he lets her, and neither of them says the name again.</p>[[Leave it with him.->Location_underworld_strip]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_cain_opens">>
<<set $game_state.current_node = "cap_cain_opens.base">>
<<script>>setup.markCanvasTriggered("cap_cain_opens");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_cain_opens.base") === -1) { vn.push("cap_cain_opens.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "cain_named_grier", "set");<</script>><img src="./videos/scenes/cain_at_the_cot.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The tap is running somewhere behind the hull and her bag is under the cot where she left it, and there is a man sitting on the end of the pad with a grey coat folded over his knee.</p><span id="cascade-b2-beat-0"><p>Kess sleeps four feet of steel away with the door on a latch. The latch is still on. She does not ask.</p><span id="cascade-b2-beat-1"><<linkreplace "Say something.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You said I could ask and you would answer. Then you said nothing at all.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I wanted to know whether you would come looking for me. You did not. That was worth knowing.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Ask what he is doing here.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And now you are on my bed.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> It is the only room you have got. I have looked.</div></div><p>He stands and puts the coat on and holds the door, and does not explain where they are going, and does not say she has to.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Head down for the middle of it. You will not like that part and it does not get better if I lie about it first.</div></div>[[Go with him.->Location_cain_lab]]
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cain_comes_for_her">>
<<set $game_state.current_node = "cain_comes_for_her.base">>
<<script>>setup.markCanvasTriggered("cain_comes_for_her");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cain_comes_for_her.base") === -1) { vn.push("cain_comes_for_her.base"); }<</script>>
<<script>>advanceTime(45);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "taken_to_lab", "set");<</script>><p>She gets back to the berth somewhere in the small hours with eleven years of a man's business in her head and nowhere to put any of it.</p><span id="cascade-b1-beat-0"><p>The pad, the tap, the hull creaking on its blocks outside. She lies down and does not sleep, and the sentence that keeps coming back is not the one about Cain being weak or the one about eleven years of paper.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Could be a fortnight. Could be tonight. He's never once told me he was coming.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Turn it over.">><p>So it is not a question of finding him. Nobody finds him. That is the whole of what eleven years of arrangement bought Bastien, and Bastien is the closest thing he has to a friend.</p><p>It is a question of being in that room. And she is in that room, four nights out of six, with a tray.</p><span id="cascade-b1-beat-2"><<linkreplace "Follow it.">><p>Which means the work is already done. She does not have to do anything clever. She has to keep turning up and let a door open behind her, and one of those nights the man she was built to kill will walk through it.</p><span id="cascade-b1-beat-3"><<linkreplace "Then what.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Then what.</div></div><p>She has no answer and she works at it for an hour and still has no answer, and what she gets instead is a list of things she does not know.</p><span id="cascade-b1-beat-4"><<linkreplace "Count them.">><p>Whether the drain even opens on a thing built the way she is built. She has fired it at nine men and not once at something with a core in it, and there is nobody to ask.</p><p>Whether he fights. Whether he is fast. Whether he would look at her once and walk straight back out through the alley door and never come to that room again.</p><span id="cascade-b1-beat-5"><<linkreplace "And the last one.">><p>And whether she wants to do anything to him at all. That is the one she stops on, and does not pick back up.</p><span id="cascade-b1-beat-6"><<linkreplace "Take what there is.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> None of it can be worked out from a cot in the dark. All of it gets decided in about four seconds in a room she does not control. So decide the one part that does not need him in it.</div></div><p>She is not going to be standing there with nothing in her hands.</p><span id="cascade-b1-beat-7"><<linkreplace "Go through the loadout.">><p>Not the emitter. One core feeds one weapon and the drain has to be the live one every night she goes through that door, because the drain is the entire reason she is allowed through it.</p><p>And a Vance field unit in her coat lining comes out of it at the door, in a man's hand, in front of forty people who all work the same floor she does.</p><p>So: something cheap. Something that runs off nothing and owes the company nothing, that a woman working a bar floor down here would have in her coat anyway, and that survives a pat-down because it is exactly as unremarkable as it looks.</p><p>It is not a plan. She knows it is not a plan. It is the one piece of the night she can buy in advance, and she is going to go and buy it in the morning.</p>[[Sleep on it.->Location_the_cot]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_wait">>
<<set $game_state.current_node = "cap_the_wait.base">>
<<script>>setup.markCanvasTriggered("cap_the_wait");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_wait.base") === -1) { vn.push("cap_the_wait.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "plan_made", "set");<</script>><p>Long benches, work-lamps, the frame standing open at the far end. The door he did not lock is where it was.</p>
<<set $game_state.current_canvas = "cain_lab_offhours">>
<<set $game_state.current_node = "cain_lab_offhours.base">>
<<script>>setup.markCanvasTriggered("cain_lab_offhours");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cain_lab_offhours.base") === -1) { vn.push("cain_lab_offhours.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Out, and up.->Location_underworld_strip]]<img src="./videos/locations/bastien_backroom.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "npc_at_location", "location_id": "bastien_backroom", "npc_id": "npc_bastien", "operator": "is_present"}]})>>
<p>He is at the desk with the lamp on and does not look up when she goes. The door onto the bar is on the latch from this side, the way it always is, and the stools are down.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "npc_at_location", "location_id": "bastien_backroom", "npc_id": "npc_bastien", "operator": "is_absent"}]})>>
<p>The chair that sees the door is empty and the lamp over the desk is off. He goes when he goes and he does not say so, and nobody who works here has ever been told where.</p><p>The door onto the bar is on the latch from this side. That is the only courtesy the room has ever shown her. She lets herself out through a room with the stools up on the tables.</p>
<</if>>
<<set $game_state.current_canvas = "bastien_backroom_offhours">>
<<set $game_state.current_node = "bastien_backroom_offhours.base">>
<<script>>setup.markCanvasTriggered("bastien_backroom_offhours");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("bastien_backroom_offhours.base") === -1) { vn.push("bastien_backroom_offhours.base"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Let yourself out.->Location_underworld_bar]]<img src="./videos/scenes/cain_lab_bench.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She does not know where it is. Twenty minutes with her head down and two changes of direction, and then a door, and then this.</p><span id="cascade-b2-beat-0"><p>Long benches under work-lamps. Everything on them laid out in order, and none of it bought new. Every piece has been taken off something that could afford it.</p><span id="cascade-b2-beat-1"><<linkreplace "Look at the walls.">><p>And the paper. Floor to ceiling on two sides, filed and stacked and annotated in a hand that presses hard enough to emboss the sheet under it. Eleven years of a company being taken apart on a desk.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> This is where it went. All of it. Every envelope through that door, every box file against that wall, for eleven years. It came here and it got read.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Look at the far end.">><p>At the far end of the room, upright and empty, a body-frame. Not a rack and not a jig. The shape of a person, standing open, with the cabling dressed back and labelled.</p><span id="cascade-b2-beat-3"><<linkreplace "Understand what it is.">><p>It is not for holding somebody down. It is for getting into. There is a mirror bolted where the head would be, angled so that whoever is standing in it can watch their own hands work.</p><span id="cascade-b2-beat-4"><<linkreplace "Keep the weapon up.">><p>She has not lowered the taser since the alley. Her arm has been up the whole walk and it is starting to shake and she does not lower it.</p><span id="cascade-b2-beat-5"><<linkreplace "Watch him.">><p>He shuts the door behind them and does not lock it. Takes the grey coat off. Puts it over the back of a chair, and stands at the bench with his back to her, and washes his hands.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Sit down or don't. The chair by the frame is the only one that holds weight.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Ask.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You came through the far door of that cell for me and you would not say why.</div></div><p>He keeps washing his hands.</p><span id="cascade-b2-beat-7"><<linkreplace "Ask properly.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> They built me to kill you. I have had your name in my file since before I could hold it.</div></div><p>The water goes off.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I know what they built you for. I have read the same page you have.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Raise it.">><p>She gets both hands on the thing and brings it up level, and it is a thirty-coin piece of grey plastic and they both know exactly what it is worth in this room.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Your arm is going. Both hands will not fix that and neither will the thing in them.</div></div><span id="cascade-b2-beat-9"><<linkreplace "Wait for him to turn round.">><p>He dries his hands on a cloth, without hurrying, the way Kess dries his hands. Then he turns round and looks at her properly for the first time since the alley. At her face, which nobody has done since she bought a different one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Now put down the weapon, Wren.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Nobody has said that name to her since the penthouse. Nobody down here has ever heard it. There is a hundred and twenty coin of somebody else on her face and he has looked at it once and gone straight through.</div></div>[[Don't.->Location_underworld_strip]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_lab">>
<<set $game_state.current_node = "cap_the_lab.base">>
<<script>>setup.markCanvasTriggered("cap_the_lab");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_lab.base") === -1) { vn.push("cap_the_lab.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "lab_seen", "set");<</script>><img src="./videos/locations/bastien_backroom.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>An evening like the other ones. He is in the chair with a drink he is not drinking, working round to the same question he has been working round to since she first stood in this room.</p><span id="cascade-b2-beat-0"><p>Then the bar goes quiet, and it is the wrong quiet. Not a fight going up. A room deciding all at once to be somewhere else.</p><p>Bastien is out of the chair before she has finished hearing it, and he is fast for a man his age, and that tells her he has been waiting years for this exact noise.</p><span id="cascade-b2-beat-1"><<linkreplace "Ask.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What is it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Alley side. Now. Don't stop for your coat and don't go through the bar.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Don't move.">><p>It is the first thing he has ever said to her that was for her benefit, and she does not take it, because the whole reason she is standing in this room is standing in this room.</p><span id="cascade-b2-beat-3"><<linkreplace "The alley door.">><p>The alley door opens without being knocked on. Whoever comes through it does not hurry either, and Bastien's whole shape changes.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> You're late.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Listen.">><p>"I know what I am." The voice is low and unhurried and there is old smoke under it, and she has heard it once, through a wall, on a floor, going through her wrong.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Three of them came down the strip. Not police. Not anybody's crew.</div></div><p>"I counted them from the water. Get your coat."</p><span id="cascade-b2-beat-5"><<linkreplace "Stand very still.">><p>Big through the shoulders. Grey coat. He does not look at her once, because she is a barmaid in a room he needs Bastien out of, and there is nothing in the world less interesting than that.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Cain.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Watch them.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> The wall. Eleven years of the wall, and you want me to walk out and leave it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I want you alive and the wall is paper. Bastien. Now.</div></div><p>And Bastien picks up his coat, because he is going to go, and when he goes the other one goes with him.</p><span id="cascade-b2-beat-7"><<linkreplace "Do the arithmetic.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> All of it for this. The face, the shifts, the hands on her in front of forty people. One room, on the chance of one night. And it is this one, and it is walking out of the door in front of her.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Reach for it.">><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_through", "operator": "gte", "value": 1}]})>>
<p>It is in the lining where it has been all night, because he went over that coat and did not find it.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_through", "operator": "lt", "value": 1}]})>>
<p>It is on his desk where he put it at the door, two feet behind her, and she has it in her hand before either of them has finished turning round.</p>
<</if>><span id="cascade-b2-beat-9"><<linkreplace "Put him down.">><p>She puts it against the back of Bastien's neck and holds the switch until his legs go, and he drops into his own good chair and out of it onto the boards, and the coat goes with him.</p><span id="cascade-b2-beat-10"><<linkreplace "Face him.">><p>The grey coat comes round fast enough that she does not see it happen, and then there is a hand on her throat and her back against the file wall and a face eight inches from hers that is not angry the way she expected angry to look.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I have questions and we are not doing them here.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Wait.">><p>He does not answer. His eyes go off her face, down and left, to the side of her neck under the jaw. To a small brown mark she has never once been asked about by anybody, in two years, in any room.</p><p>The hand comes off her throat.</p><span id="cascade-b2-beat-12"><<linkreplace "Say something.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Don't.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> I wasn't going to.</div></div><p>A beat.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Not here.</div></div><span id="cascade-b2-beat-13"><<linkreplace "Then the wall goes.">><p>The wall between the room and the bar stops being a wall. Through it, unhurried, three of them. Chrome-perfect, hands empty, nothing moving behind the eyes, walking into a burning room the way you walk into a kitchen.</p><p>One of them looks at her for exactly as long as it takes and says, flatly, a designation. Four letters and eleven digits, and she has read them once, on her own page, on a bench at the breaking docks.</p><span id="cascade-b2-beat-14"><<linkreplace "Understand it.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> They are not here for Bastien. They have never been here for Bastien.</div></div><span id="cascade-b2-beat-15"><<linkreplace "Go.">><img src="./videos/scenes/backroom_burning.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Cain takes her off the wall by the arm and out through the alley door, and behind them the files go up along their whole length at once. That is not how paper burns unless somebody has been thorough about it.</p><p>She looks back from the alley for exactly as long as she gets, and what is on the floor of that room is a chair, a coat, and nothing she can see.</p><p>They come up the strip against the whole district going the other way. He does not have Bastien, he does not have the wall, and he has not once let go of her arm.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> There's a place. You can ask me there, and I'll answer, and then you can decide what you want to do about it.</div></div>[[Go with him.->Location_cain_lab]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_raid">>
<<set $game_state.current_node = "cap_the_raid.base">>
<<script>>setup.markCanvasTriggered("cap_the_raid");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_raid.base") === -1) { vn.push("cap_the_raid.base"); }<</script>>
<<script>>advanceTime(90);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "raid_done", "set");setup.applyAndNotifyFlag("player", null, "cain_named", "set");<</script>><p>He comes apart under her hand and stays there. The careful weight of him comes loose down her arm. Eleven years of holding one thing, going soft.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The files against that wall. Who are they for.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Let him answer.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> One man. Same man for eleven years. Everything else I sell is so that nobody wonders why I buy.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> The bar's for the same reason. You can't run paper out of a room nobody's allowed to come to.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Ask which man.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Name.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Cain.</div></div><p>She has been carrying that name since a briefing room on the ninetieth floor. It has never once had a person on the end of it.</p><span id="cascade-b1-beat-3"><<linkreplace "Ask what he wants with it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What does he do with company paper.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Rebuilds himself out of it. He's an early one — first or near it — and next to what they turn out now he's a hand-cut thing with a lot of miles on it.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Push.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> He can't walk at Vance the way he is. He's tried something like it twice and both times he came back needing work I couldn't get him. So he takes them apart on paper instead and puts the good bits in himself, a year at a time.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Eleven years of it. He is a great deal harder to kill than he was when I met him and he is still nowhere near enough.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Ask where he is.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where does he live.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> No idea. Eleven years and I've never had an address off him and never asked for one. That's not trust, that's the arrangement working.</div></div><span id="cascade-b1-beat-6"><<linkreplace "Ask how he finds him, then.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then how do you hand anything over.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> I don't. He comes here. Whenever he likes, through the alley door, and sits in that chair you're not sitting in, and takes what's ready.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Could be a fortnight. Could be tonight. He's never once told me he was coming in eleven years.</div></div><span id="cascade-b1-beat-7"><<linkreplace "Ask if he's ever asked for anything else.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Has he ever wanted something that wasn't paper.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Once. I had a girl in a room under here that I'd bought off a bad debt, and I was finding out what she was, and he came through that far door in a state I'd never seen on him and took her out.</div></div><span id="cascade-b1-beat-8"><<linkreplace "Keep him talking.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Furious. In a hurry. Wouldn't say why he cared and wouldn't be argued with, and I let him, because I've made a lot of money out of not arguing with him.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> And I still don't know why that one. He's walked past worse in this bar. I've asked him twice and he's changed the subject twice, and he's never changed a subject on me about anything else.</div></div><span id="cascade-b1-beat-9"><<linkreplace "Hold on to him.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> The man who bought her paperwork. The man who came through that door for her. The man they built her to kill. Three files in Mercer's office and one person standing in all of them, and she took a job carrying trays in his supplier's bar to get this far.</div></div><span id="cascade-b1-beat-10"><<linkreplace "Let him surface.">><p>He comes back propped against the desk with his shirt open, agreeable and empty and none the wiser.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> I've lost the thread. Where were we. Sit down. No, don't. You never do.</div></div><p>She takes the dress off his desk and puts it back on, and goes out through the bar carrying eleven years of his and none of her own.</p><p>Behind her the room is quiet, and the man in it is going to wake up pleased, and the chair by the wall is empty and will not always be.</p>[[Out through the bar.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "bastien_drain_canvas">>
<<set $game_state.current_node = "bastien_drain_canvas.d0">>
<<script>>setup.markCanvasTriggered("bastien_drain_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("bastien_drain_canvas.d0") === -1) { vn.push("bastien_drain_canvas.d0"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.showEffectNotification();<</script>><p>His cock is deep in her ass and he cums holding her down on the desk, the way he does it now, and the drain opens off her hand on his wrist with no discovery left in it. Just the careful weight of him coming loose and the hour going with it. He wakes agreeable and none the wiser and asks her to sit down, and she does not.</p><p>She asks the only question worth asking twice, and gets the same answer twice: he comes when he comes, and he has never once said he was coming.</p>
<<set $game_state.current_canvas = "bastien_drain_canvas">>
<<set $game_state.current_node = "bastien_drain_canvas.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("bastien_drain_canvas.done") === -1) { vn.push("bastien_drain_canvas.done"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
[[Out through the bar.->Location_underworld_bar]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_finish_facial_t5"] to ($game_state.media_cycle["sex_bastien_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_finish_facial_t5/c4cdbc577a1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_finish_facial_t5/c21cc2b9f69.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_finish_facial_t5/c66861dfacf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_finish_facial_t5/ca90212e938.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He pulls out of her mouth and finishes across her face, cum on her cheek and her lashes and running off her chin, and looks down at it the way a man looks at a result. Nothing comes loose but him. The drain stays shut. It only ever opens the one way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There. There's a cloth on the desk and I'd rather you used that than your sleeve, because you're going back out on my floor after this.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_finish_inside_t5"] to ($game_state.media_cycle["sex_bastien_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_finish_inside_t5/c0e65426219.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_finish_inside_t5/c145be340d4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_finish_inside_t5/c2090f3207c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_finish_inside_t5/cced25384bc.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes deep in her cunt with both hands locked on her hips, holds her there while it goes through him, and lets her up when he is ready and not before. She has taken nothing. Not this way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Stay down a minute. You'll walk out of here with it in you and go and carry a tray, and that's the whole of what I wanted tonight.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_finish_ass_t5"] to ($game_state.media_cycle["sex_bastien_finish_ass_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_finish_ass_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_finish_ass_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_finish_ass_t5/c1bd134c597.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_finish_ass_t5/c79e5de0c9c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_finish_ass_t5/c306a472344.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_finish_ass_t5/cd5e48ff23c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He drives all the way into her ass and stays there while he cums, dead still, breathing out through his teeth. Her hand is on his wrist, skin on skin, and this time the shudder goes through him and takes the door with it.</p>
<</if>>
<<set $game_state.current_canvas = "loop_bastien_finisher">>
<<set $game_state.current_node = "loop_bastien_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_bastien_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_bastien_finisher.climax") === -1) { vn.push("loop_bastien_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Get dressed." "Location_bastien_backroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_finisher:cc0");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Take him." "Canvas_bastien_drain_canvas_Node_d0">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bastien_drains_done", "add", 1.0, true, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_finisher:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Take him." "Canvas_bastien_drain_canvas_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bastien_drains_done", "add", 1.0, true, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_finisher:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "gte", "value": 1}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_bastien_finisher = [{"text": "Get dressed.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Take him.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "lt", "value": 1}]}}, {"text": "Take him.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "gte", "value": 1}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_bastien_finisher",
choices: window._engineNoExitsDiag_loop_bastien_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_bastien_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_bastien_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_backroom_t4"] to ($game_state.media_cycle["sex_bastien_backroom_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_backroom_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_backroom_t4"]>><<if _mc is 0>><video src="./videos/sex/bastien_backroom_t4/c2ec1b2bdb3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_backroom_t4/c2fba6bdb4b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_backroom_t4/cd82d6add2a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_backroom_t4/cf65019b50e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He puts down the drink he has not touched and strips the dress off her over her head. She stands naked on his floor while he looks her over. Tits, hips, the closed seam. He takes his time about it, and has his cock out before he has finished looking.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> I don't do this because I want you. I do it because it's the only way anybody down here is ever honest with me, and I've a stack of questions about you and no answers at all.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Take your time. The door's shut and there's nobody in this city who knocks on it.</div></div>
<<set $game_state.current_canvas = "loop_bastien_backroom">>
<<set $game_state.current_node = "loop_bastien_backroom.intro">>
<<script>>setup.markCanvasTriggered("loop_bastien_backroom");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_bastien_backroom.intro") === -1) { vn.push("loop_bastien_backroom.intro"); }<</script>>
<<nobr>>
<<link "Get on your knees." "Canvas_loop_bastien_backroom_Node_base_oral_bastien">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_loop_oral_t5"] to ($game_state.media_cycle["sex_bastien_loop_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_loop_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_loop_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_loop_oral_t5/c2bf86480e9.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_loop_oral_t5/c8c8352e5f1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_loop_oral_t5/cdb0494bfff.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_loop_oral_t5/cf55be9005d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees on his floor, hands flat on her own thighs, sucking his cock at the pace he sets. He holds her head still and fucks her throat down to his balls, unhurried, and her jaw aches long before he is near done.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There. Look up at me while you do it. I am paying for the eyes as much as the mouth.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Slower. You work for me, and my staff do not rush.</div></div>
<<set $game_state.current_canvas = "loop_bastien_backroom">>
<<set $game_state.current_node = "loop_bastien_backroom.base_oral_bastien">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_bastien_backroom.base_oral_bastien") === -1) { vn.push("loop_bastien_backroom.base_oral_bastien"); }<</script>>
<<nobr>>
<<link "Keep him in your mouth." "Canvas_loop_bastien_backroom_Node_base_oral_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Stand up and let him have you." "Canvas_loop_bastien_backroom_Node_base_vaginal_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_backroom:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_bastien_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_backroom:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_loop_vaginal_t5"] to ($game_state.media_cycle["sex_bastien_loop_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_loop_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_loop_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_loop_vaginal_t5/c6230c2e2ee.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_loop_vaginal_t5/c7309b55634.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_loop_vaginal_t5/cae7122754c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_loop_vaginal_t5/ce8e822b386.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Bent face-down over the bare desk, his cock in her cunt, one hand spread flat between her shoulder blades and the other on her hip. He fucks her slowly and the bar comes through the wall in pieces around it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Christ, you are wet for a woman who wants nothing. That is not a compliment. It is the first honest thing you have done since you walked into my bar.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Stay down. My floor, my time, my desk. And you are the only one of the four that talks.</div></div>
<<set $game_state.current_canvas = "loop_bastien_backroom">>
<<set $game_state.current_node = "loop_bastien_backroom.base_vaginal_bastien">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_bastien_backroom.base_vaginal_bastien") === -1) { vn.push("loop_bastien_backroom.base_vaginal_bastien"); }<</script>>
<<nobr>>
<<link "Let him have it." "Canvas_loop_bastien_backroom_Node_base_vaginal_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_loop_bastien_backroom_Node_base_oral_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn over — give him your ass." "Canvas_loop_bastien_backroom_Node_base_anal_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_backroom:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_bastien_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_backroom:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_loop_anal_t5"] to ($game_state.media_cycle["sex_bastien_loop_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_loop_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_loop_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_loop_anal_t5/c4ae2180a42.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_loop_anal_t5/c23b29daeb6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_loop_anal_t5/c188632a80b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_loop_anal_t5/c3437092145.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She gets a hand back around his wrist, skin on skin, and holds it there. That is the seat, and the drain sits in the contact and waits.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> This is the one they all say no to. You didn't even change your breathing.</div></div><p>He pulls out of her cunt and puts his cock in her ass instead, one hand flat between her shoulder blades, holding her down on the desk while he works the whole length of himself into her a piece at a time.</p>
<<set $game_state.current_canvas = "loop_bastien_backroom">>
<<set $game_state.current_node = "loop_bastien_backroom.base_anal_bastien">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_bastien_backroom.base_anal_bastien") === -1) { vn.push("loop_bastien_backroom.base_anal_bastien"); }<</script>>
<<nobr>>
<<link "Take it." "Canvas_loop_bastien_backroom_Node_base_anal_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Let him get his hands in your hair." "Canvas_loop_bastien_backroom_Node_base_anal_hard_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 10), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on him." "Canvas_loop_bastien_backroom_Node_base_vaginal_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_backroom:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — and reach for it." "Canvas_loop_bastien_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_backroom:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bastien_loop_anal_hard_t5"] to ($game_state.media_cycle["sex_bastien_loop_anal_hard_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_bastien_loop_anal_hard_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_bastien_loop_anal_hard_t5"]>><<if _mc is 0>><video src="./videos/sex/bastien_loop_anal_hard_t5/c90ec7df3c3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bastien_loop_anal_hard_t5/ca7213f0fbd.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/bastien_loop_anal_hard_t5/ccca1f7e448.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bastien_loop_anal_hard_t5/cd0495942b4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Her hand stays on his wrist through all of it, skin on skin. The hand is the job and the rest is the price of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There she is. All that time with nothing on your face, and I get this out of you by doing that.</div></div><p>He gathers her hair in his fist and hauls her head up off the wood, and stops being unhurried about any of it. Fucking her ass hard enough to walk the desk, his other hand clamped white on her hip, her tits dragging the bare boards.</p>
<<set $game_state.current_canvas = "loop_bastien_backroom">>
<<set $game_state.current_node = "loop_bastien_backroom.base_anal_hard_bastien">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_bastien_backroom.base_anal_hard_bastien") === -1) { vn.push("loop_bastien_backroom.base_anal_hard_bastien"); }<</script>>
<<nobr>>
<<link "Take it like that." "Canvas_loop_bastien_backroom_Node_base_anal_hard_bastien">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 10), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down onto the desk." "Canvas_loop_bastien_backroom_Node_base_anal_bastien">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_bastien_backroom:cc3') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — and reach for it." "Canvas_loop_bastien_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_bastien_backroom:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><img src="./videos/locations/bastien_backroom.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The door shuts and the bar stops existing. He takes the chair that sees it and leaves her the room.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "lt", "value": 1}]})>>
<p>Along the whole of the far wall, floor to shoulder, box files. Dated spines, a hand that presses hard, and eleven years of somebody's company going quietly into a room behind a bar.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bastien_drains_done", "operator": "gte", "value": 1}]})>>
<p>She has had everything out of this man that he has, and she keeps coming back to sit in the one room in the city that the other one walks into whenever he feels like it.</p>
<</if>>
<<set $game_state.current_canvas = "hub_bastien">>
<<set $game_state.current_node = "hub_bastien.base">>
<<script>>setup.markCanvasTriggered("hub_bastien");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_bastien.base") === -1) { vn.push("hub_bastien.base"); }<</script>>
<<nobr>>
<<link "Let him talk." "Canvas_hub_bastien_Node_talk">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Let him take you in the back." "Canvas_loop_bastien_backroom_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Step away." "Location_bastien_backroom">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<set _bp to random(0, 3)>>
<<if _bp is 0>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> You don't drink. All this time on my floor and not one glass, and you carry them all night. I've had two people in twenty years I could say that about and I owned them both.</div></div>
<<elseif _bp is 1>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Everyone who comes through that door wants something off me. You're the first in a long time who hasn't said what. I'll wait. I'm good at that and there's nothing else I want.</div></div>
<<elseif _bp is 2>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> You looked at this door exactly once, and I know which night it was. Never again after that. And everybody looks, love. It's the not-looking that's the work.</div></div>
<<else>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Somebody spent real money putting you back together and you're carrying trays for fifteen a night. I've been turning that over since the night you walked in and I've got nowhere with it. That is why you're in here.</div></div>
<</if>><p>He talks the way a man talks who has already decided he will find out, and has no reason to hurry.</p>
<<set $game_state.current_canvas = "hub_bastien">>
<<set $game_state.current_node = "hub_bastien.talk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_bastien.talk") === -1) { vn.push("hub_bastien.talk"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "add", 2.0, true, null);setup.showEffectNotification();<</script>>
[[Say nothing worth having.->Location_bastien_backroom]]<img src="./videos/locations/underworld_bar.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The back door has no handle on this side. He opens it himself and does not step out of the way.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Coat.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Nobody minds. They've all had it. It's the ones who mind that are carrying.</div></div><p>All those nights of him deciding things about her from a chair, and this is the first sentence he has ever aimed at her face.</p><span id="cascade-b2-beat-1"><<linkreplace "Give him the coat.">><p>He goes through it standing up, in the light, with the bar behind her doing what the bar does when he is in the room.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Lining, cuffs, the seam under the arm. That's where a clever one puts it, and you look clever.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Then the rest.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Turn round. Skirt up at the back. No, I don't need it off. I need to see the base of your spine.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> I'd do this to a man twice your size and he'd stand there and thank me for it.</div></div><p>There is a bar behind her with forty people at it and half of them work the same floor she does. She turns round.</p><span id="cascade-b2-beat-3"><<linkreplace "Stand still.">><p>His hand finds the ridge straight to it. That means he has done this to somebody with one before.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Well now. Somebody's had you open.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Closed neat, too. That's a shipwright's stitch. You've been down the breaking docks with the rest of the desperate, and you've been down there more than once.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Say nothing.">><p>She lets him have it, because it is true, because it is the least dangerous true thing about her, and because a woman who has been under a ship-breaker's hands for money is the most ordinary person in this district.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> I like that. Everyone who comes through this door is a story somebody's tidied up. You've not bothered tidying.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Wait for the verdict.">><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 30}]})>>
<p>The coat comes back with the lining flat and the weight still in it, and his hand went over that seam twice.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Clean. You buy your gear off my stalls — everyone does. It's why I check twice and why it's usually worth it.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 30}]})>>
<p>It comes out of the coat on the second pass. He turns it over, finds the thumb-switch, and doesn't press it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> This stays on the desk. You'll have it back at the door and I'll not ask, because every woman working a floor down here carries one and the ones who don't are somebody's already.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "lt", "value": 1}]})>>
<p>He goes over the coat and the seam and finds what is there. That is nothing at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Nothing. Not a pin. That's either very careful or very stupid and I've not decided which yet.</div></div>
<</if>><p>He holds the door with two fingers and waits for her to walk through it in front of him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> After you. I like to watch a thing walk when it thinks it's got away with something.</div></div><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 30}]})>>
<span @class="setup.isChoiceVisited('bastien_door_search:cc0') ? '' : 'unlocked-choice'">
<<link "Go through." "Location_bastien_backroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_through", "set", 1.0, true, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("bastien_door_search:cc0");<</script>><<script>>advanceTime(15);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 30}]})>>
<span @class="setup.isChoiceVisited('bastien_door_search:cc1') ? '' : 'unlocked-choice'">
<<link "Go through." "Location_bastien_backroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_through", "set", 0.0, true, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("bastien_door_search:cc1");<</script>><<script>>advanceTime(15);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('bastien_door_search:cc2') ? '' : 'unlocked-choice'">
<<link "Go through." "Location_bastien_backroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_through", "set", 0.0, true, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("bastien_door_search:cc2");<</script>><<script>>advanceTime(15);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 30}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 30}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "lt", "value": 1}]})))>>
<<script>>
try {
window._engineNoExitsDiag_bastien_door_search = [{"text": "Go through.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 30}]}}, {"text": "Go through.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 30}]}}, {"text": "Go through.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "taser_held", "operator": "lt", "value": 1}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "bastien_door_search",
choices: window._engineNoExitsDiag_bastien_door_search,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_bastien_door_search>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas bastien_door_search</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Location_underworld_bar]]
<</if>>
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "bastien_door_search">>
<<set $game_state.current_node = "bastien_door_search.base">>
<<script>>setup.markCanvasTriggered("bastien_door_search");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("bastien_door_search.base") === -1) { vn.push("bastien_door_search.base"); }<</script>><p>Sol waits until the last of the near tables has gone up and the room is down to the men who will be here at closing. Then he comes along the counter and stands in front of her instead of beside her, which he has never done.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Tomorrow night you take the tray through the back.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><p>She has been working toward a version of this sentence since the night Sol put a bar cloth on the counter, and it still lands somewhere under the ribs.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You said that room isn't mine.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> It isn't. That's why it's a sending-for and not a shift.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Make him say it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You told me to think hard about that night before I got to it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> I did. You've had time to think about it and you've kept turning up, so I'll take it you thought.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Ask what it is.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What happens in there.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Business, mostly. He's a businessman, mostly.</div></div><p>It is the first time she has ever heard Sol use a pronoun for the owner.</p><span id="cascade-b1-beat-4"><<linkreplace "Ask about the door.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> You go in through the bar side. He'll do you at the door first — coat off, hands on, all of it, in front of the room. Everybody gets it. Don't take it personal and don't make a face about it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> The ones who make a face about it don't come back in.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Say yes.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> All right.</div></div><p>Sol looks at her for a second longer than he has looked at her since the night she stopped being somebody he knew, and then he goes back down the counter and does not say anything else for the rest of the shift.</p><p>She walks home up the strip working out what she will be carrying and where, and by the gate she has decided that the answer is nothing, and that she will be walking in with empty pockets and somebody else's face and nothing else at all.</p>[[Go home. Tomorrow, then.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "rung_bar_promotion_4">>
<<set $game_state.current_node = "rung_bar_promotion_4.base">>
<<script>>setup.markCanvasTriggered("rung_bar_promotion_4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_bar_promotion_4.base") === -1) { vn.push("rung_bar_promotion_4.base"); }<</script>>
<<script>>advanceTime(90);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 4.0, true, null);setup.showEffectNotification();<</script>><p>It is on the counter when she comes in. A soft bag, folded shut, with nothing written on it and nobody standing near it.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> That's yours.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> From.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> It was on the counter when I opened up.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Open it.">><p>A dress. Short, thin, cut close, and the right size. That is the part that sits coldest. Somebody has looked at her carefully enough to be right about it, from a chair, across a room, over every shift she has worked.</p><span id="cascade-b1-beat-2"><<linkreplace "Look at Sol.">><p>Sol is at the far taps, busying himself with a barrel that is already fine. He has been at that barrel since she came through the door.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Sol.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> I've outlasted four owners by handing things over and not saying anything after. I'm not going to be good at this and I'd rather not try.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Think about the door.">><p>The door out is eight feet behind her and nothing in this room is holding it shut. Nobody signed for her. Nobody has a key. She could put the bag down and be up the strip inside a minute and there would be no consequence at all except the one that matters.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> And then she is a woman with a hundred and twenty coin of face and no way through that door.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Ask where.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where am I meant to put this on.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Staff toilet at the back. Bolt turns. There's a hook on the door and I'd use it, because whatever you came in wearing isn't going on that floor.</div></div><p>It is the most consideration the Undertow has ever shown her and it takes him four seconds.</p><span id="cascade-b1-beat-5"><<linkreplace "Go back up.">><p>The room clocks it in about a second and a half. The talk drops, not much, the way it does when weather changes outside a window, and then it comes back up around her at a slightly different pitch and stays there.</p><p>The back door does not open all night. She works the floor in it until closing, and the man who chose it stays out of sight the whole time, leaving the question of whether he was right about the size.</p>[[Work the floor.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "rung_bar_promotion_3">>
<<set $game_state.current_node = "rung_bar_promotion_3.base">>
<<script>>setup.markCanvasTriggered("rung_bar_promotion_3");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_bar_promotion_3.base") === -1) { vn.push("rung_bar_promotion_3.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 3.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("dress_undertow");setup.showEffectNotification();<</script>><img src="./videos/scenes/bastien_back_door.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Another shift. Tray, three steps, the near tables. Halfway through the night the door at the back is open a few inches, which it has not been once since she started.</p><span id="cascade-b2-beat-0"><p>She does not look at it, because that is the rule and because looking at it is what new ones do. She clears the near tables twice instead.</p><span id="cascade-b2-beat-1"><<linkreplace "Look.">><p>Then she looks.</p><p>Warm light, a desk with nothing on it, and a chair set at the angle a chair is set at when a man wants the door in front of him all evening. There is somebody in it.</p><span id="cascade-b2-beat-2"><<linkreplace "Keep looking.">><p>Her hands know before she does. The tray goes very slightly heavier and something under her sternum that has been quiet since Kess closed her up does a thing that is not quite the old climb.</p><span id="cascade-b2-beat-3"><<linkreplace "Name it.">><p>Older than the voice through the wall. Grey through the sides now, a good coat over a chair back, a drink at his elbow that he is not drinking and, she would bet the whole hundred and twenty, has not touched all night.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Bastien.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Don't drop the tray.">><p>She does not drop the tray. That is the entire achievement of the next four seconds and she will think about it later with something close to pride.</p><p>A chair pulled up to a mattress. A thumb wiping her chest clean to read what was underneath. A pen clicking, in a room with no clock in it.</p><span id="cascade-b2-beat-5"><<linkreplace "Do the arithmetic.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A man who has been collecting a company's paper for years, in a room that takes envelopes in one direction only, behind a bar he owns and never visits. She has been carrying trays inside the answer since the night she started.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Wait for him to see you.">><p>He looks up. She stands in the middle of his floor holding four empty glasses and lets him.</p><p>In all that time in the cell he never once looked at her face. He looked at the light under her sternum, and he wrote what it said in a notebook, and the light is out now.</p><span id="cascade-b2-beat-7"><<linkreplace "Let him look.">><p>So what is standing in his bar is a woman with a tray and somebody else's face, and what he is remembering, if he is remembering anything at all, is a number in a column.</p><p>He looks at her the way a man looks at a chair he is thinking of moving. Then he looks back down at the desk.</p><span id="cascade-b2-beat-8"><<linkreplace "Finish the tables.">><p>The door shuts a minute later, from the inside, without anybody crossing to it.</p><span id="cascade-b2-beat-9"><<linkreplace "Take the glasses back.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> You're on the taps from tomorrow.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Says who.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Says the roster. Don't make it a conversation. I've been doing this thirty years and the roster's never once been my idea.</div></div><p>She works the rest of the shift and her hands stay steady the whole way through it. That is a thing she notices and does not examine.</p><p>At closing she walks up the strip in somebody else's coat, past the market, past the gate, down to a dock where a man is cutting a hull open under a lamp, and she does not tell him either.</p>[[Go home and say nothing.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_bastien_notices">>
<<set $game_state.current_node = "cap_bastien_notices.base">>
<<script>>setup.markCanvasTriggered("cap_bastien_notices");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_bastien_notices.base") === -1) { vn.push("cap_bastien_notices.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 2.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "bastien_seen", "set");<</script>><img src="./videos/locations/underworld_bar.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Second night at the same stool. He rings her drink unasked this time, which down here is most of a conversation.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Are you hiring.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Always. It's that kind of room.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Wait for the terms.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Glasses, tables, and you carry a full tray down three steps without looking at your feet. Fifteen a shift and you keep whatever's left on the bar. That is nothing, because the men in here are careful with money.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Do the arithmetic out loud.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The House pays thirty a head.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> The House pays thirty a head. So go and work at The House.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Don't.">><p>Thirty a head buys the cot and the line and a part, and she has been doing exactly that arithmetic since the night Kess first put her on the feed line, and every answer it ever gave her belonged to somebody else's errand.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Fifteen a shift, six nights a week, standing in a room with a door in it. That is not what the money is for.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Take it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Fifteen's fine.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Course it is. You've sat there and not once tried to tell me anything about yourself, and that's the whole interview.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Ask who you'd be working for.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Whose bar is it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Mine, six nights out of seven. Somebody's on the paper. He's never once come down to look at it and I've never once gone up to ask.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Push a little.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You've never met him.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> I've outlasted four owners. You don't do that by learning which one you've got. An owner you never see is an owner who never asks you a question you can't answer.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Ask about the back.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> And that door's not yours. Men use that room. They come in the alley side and they go out the alley side and what they want from this bar comes to them, it doesn't get fetched.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> If you're ever in there it'll be because somebody sent for you, and I'd think hard about that night before you got to it.</div></div><p>He puts a bar cloth on the counter in front of her. That is the whole of the paperwork, and goes back down the taps.</p><p>She ties her hair back with somebody else's hands and starts on the glasses at the near end, where she can see the door.</p>[[Start on the glasses.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_sol_hires">>
<<set $game_state.current_node = "cap_sol_hires.base">>
<<script>>setup.markCanvasTriggered("cap_sol_hires");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_sol_hires.base") === -1) { vn.push("cap_sol_hires.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "bar_rung", "set", 1.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "bar_hired", "set");<</script>><img src="./videos/scenes/wren_stranger_bar.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The Undertow at nine. Same door, same three steps down, same smell of wet coats and spilled beer over old smoke.</p><span id="cascade-b2-beat-0"><p>The room does what the room does when anybody comes in: a half-second of attention, priced and dismissed. She has been getting a different half-second than that since the first night she came down those steps, and noticed it only when it stopped.</p><span id="cascade-b2-beat-1"><<linkreplace "Go to the bar.">><p>Sol comes down the counter with the towel over his shoulder and the flat, even, entirely pleasant face he keeps for people whose names he has yet to learn.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> What'll it be.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Order something.">><p>She orders the thing she always orders. He pours it, takes her coin, and rings it, and there is nothing at all in it.</p><span id="cascade-b2-beat-3"><<linkreplace "Wait for it.">><p>He does not lean. He does not do the thing where he finds a glass to wipe near her. He does not say the short flat sentence about somebody who died on the strip last week that he has been saying to her, unasked, since the second week.</p><span id="cascade-b2-beat-4"><<linkreplace "Hold still.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> It works. That is the finding, and it is the finding she paid for. A man who decided a long time ago that he liked her has looked at her twice tonight and got nothing back either time.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Look at the back door.">><p>There is a door at the back of the room with no handle on this side. She has walked past it more times than she could count and never once wondered about it, which she now thinks is itself a strange thing to be true.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> That's not a door you look at, love. New ones always do, mind. It's how I know they're new.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Say nothing much.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Just came in out of the rain.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> It's not raining.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Doesn't matter to me. Everybody comes in out of something.</div></div><p>She takes the drink to the end of the bar and sits where she can see the door with no handle, and stays until closing, and nobody asks her anything at all.</p>[[Stay till closing.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_stranger_at_the_bar">>
<<set $game_state.current_node = "cap_stranger_at_the_bar.base">>
<<script>>setup.markCanvasTriggered("cap_stranger_at_the_bar");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_stranger_at_the_bar.base") === -1) { vn.push("cap_stranger_at_the_bar.base"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "stranger_seen", "set");<</script>><img src="./videos/locations/underworld_strip.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The strip at the hour when it fills. She stands out of the traffic with her back to a wall and does the arithmetic properly instead of walking it off again.</p><span id="cascade-b2-beat-0"><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Four people. One question. A courier who protects himself, a madam who deals straight, a barman who likes her, and a stall that would sell her a person. Four different answers and the same shape underneath all of them.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Count it again.">><p>Any one of them alone is a man's own business. Rue on her own is a bad week. Sol on his own is a man with a headache.</p><p>Three of them, one after another, is not three private decisions. Somebody said something, and every one of them heard it before she asked.</p><span id="cascade-b2-beat-2"><<linkreplace "Ask who.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She took a thing out of her own spine that a company put there, and she has been walking around ever since like a woman who got away with it.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Follow it.">><p>The Reach does not close for nothing. It closes for money it is frightened of losing, and there is exactly one outfit above this water with enough of that to buy a whole street's manners at once.</p><span id="cascade-b2-beat-4"><<linkreplace "Test it.">><p>She tests it against what she saw. Nobody was frightened of her. Nobody threatened her, took her coin, or asked her to leave. Rue offered her work at the same rate as always.</p><p>That fits. A word does not have to say harm her. A word only has to say her name and not one thing more, and careful people fill in the rest themselves.</p><span id="cascade-b2-beat-5"><<linkreplace "Take the consequence.">><p>So the question is dead. Not the buyer. The buyer is still down here with a stack of paper and a habit of paying on time. Dead is her asking it.</p><span id="cascade-b2-beat-6"><<linkreplace "Think about the covers.">><p>She has done this before. Coveralls at a depot, an analyst's kit on a Vance floor, a walk and a voice and a name for each. She was good at it. It is the one thing they built her to be good at.</p><p>Both times Mercer handed her the clothes and told her whose life to get inside.</p><span id="cascade-b2-beat-7"><<linkreplace "Follow that.">><p>Whatever word is out, it has a name in it, and the name is Wren. It does not describe a woman off a boat with no history and nothing to trade but hours.</p><p>There is a row at the far end of the market where the stock has faces. Whatever they sell down there to make a person stop being findable, she can afford it or she can earn it.</p>[[Go and price it.->Location_underworld_strip]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_the_wall">>
<<set $game_state.current_node = "cap_the_wall.base">>
<<script>>setup.markCanvasTriggered("cap_the_wall");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_the_wall.base") === -1) { vn.push("cap_the_wall.base"); }<</script>>
<<script>>advanceTime(45);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "wall_understood", "set");<</script>><p>The paper stall is the old man with the new name, and the price of a thing here has never once depended on what the thing was.</p><span id="cascade-b1-beat-0"><p>She puts coin on the counter before she asks, because that is the grammar down here and it has never failed.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Company paper. Somebody's been buying it for years. I want where it goes.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><p>He looks at the coin the way a man looks at weather. He does not touch it, and not touching it takes him some effort.</p><p>"Not that," he says. "Anything else on this table and half of what's under it."</p><span id="cascade-b1-beat-2"><<linkreplace "Add to it.">><p>She adds to it. It is more than the manifests behind him are worth and they both know it.</p><p>"Still not that."</p><span id="cascade-b1-beat-3"><<linkreplace "Ask why not.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You sell people off the end of this row.</div></div><p>"I do. Take your money back, love. I'd rather you had it than left it here looking at me."</p><p>She takes it back. Four people now, and every one of them has found a different way to be perfectly reasonable at her, and not one of them has said no.</p>[[Pocket it.->Location_underworld_market]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "wall_market">>
<<set $game_state.current_node = "wall_market.base">>
<<script>>setup.markCanvasTriggered("wall_market");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("wall_market.base") === -1) { vn.push("wall_market.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "wall_refusals", "add", 1.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "wall_market_asked", "set");<</script>><p>Sol has the taps and the towel and the flat attention he gives everyone, and she has spent every night since she came down the gate earning a version of it that is not flat.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Somebody down here collects Vance paper. Years of it. You'd know who.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><p>He wipes the same clean glass he was already wiping. He is a man who has told her true things about dead men and where their people ended up, unprompted, for free.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> I would.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Wait for the rest.">><p>There is no rest. He sets the glass down and picks up another one that is also already clean.</p><span id="cascade-b1-beat-3"><<linkreplace "Ask him straight.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You've never made me ask twice.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> No.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> I'll pour for you all night and I'll not charge you for the last one. That's what I've got.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Push it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Sol.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Don't. You'll only make me say something short and then we'll both have to live in this bar afterwards.</div></div><p>He is not frightened of her and he is not ashamed. He looks like a man keeping a promise he does not enjoy having made, and she has no idea who he made it to.</p>[[Let it go.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "wall_sol">>
<<set $game_state.current_node = "wall_sol.base">>
<<script>>setup.markCanvasTriggered("wall_sol");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("wall_sol.base") === -1) { vn.push("wall_sol.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "wall_refusals", "add", 1.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "wall_sol_asked", "set");<</script>><p>Rue is doing the book, which she does in the open, because the whole of her authority down here is that her numbers are the same numbers whoever asks.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Who buys company paper on the strip. Not the fences. The one who keeps it.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Wait for it.">><p>The pen stops. It is a short stop and it is the first time since the madam took her on that Rue has taken any time at all to answer her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> That's not a thing I trade in.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Say the obvious.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You trade in who's where and who pays. That's the same trade.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> It is. And I'm still not trading in it, and I'd rather you took that as an answer than as the start of something.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Ask what changed.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You've never done that to me.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> No. And there's work upstairs at thirty a head if you want it, same as always, and I'll count it out honest, same as always.</div></div><p>The offer is real. Everything about it is exactly as straight as Rue has ever been with her, and it is being used to change the subject.</p>[[Leave her to the book.->Location_underworld_brothel]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "wall_rue">>
<<set $game_state.current_node = "wall_rue.base">>
<<script>>setup.markCanvasTriggered("wall_rue");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("wall_rue.base") === -1) { vn.push("wall_rue.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "wall_refusals", "add", 1.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "wall_rue_asked", "set");<</script>><p>He is in the corner he is always in, back to the wall, drinking at the speed of a man who intends to still be upright at closing.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The copies you carried out of Vance. Who was at the other end.</div></div><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><p>He does not put the glass down. That is his tell, and she has seen it enough times now to read it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> You know what I'm going to say. You've heard me say it about other people and you liked me for it.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Ask anyway.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I'm asking anyway.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> I don't learn a name I don't need. I've never needed that one. I put a package where I'm told and I go home, and that's thirty years of still being here.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Push.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You know the room. You've stood outside it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> I've stood outside a lot of rooms. Ask me about the ones with nothing in them and I'll talk all night.</div></div><p>That is not a man hiding something. That is a man who arranged his whole life so there would be nothing to hide, and she cannot hold it against him.</p>[[Let him drink.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "wall_colm">>
<<set $game_state.current_node = "wall_colm.base">>
<<script>>setup.markCanvasTriggered("wall_colm");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("wall_colm.base") === -1) { vn.push("wall_colm.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "wall_refusals", "add", 1.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "wall_colm_asked", "set");<</script>><img src="./videos/scenes/kess_chip_light.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The lamp is down over the bench this time, tight on one small grey thing, and the tools beside it are the fine ones.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You left it. I said I'd rather not know and I meant that too, and then it sat there looking at me.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Ask what he did.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You've had it under a light.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I've had it under two. Don't get excited. I can tell you how it was made and not one thing about what it did.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Take what there is.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's about fifteen years old. That's not a guess, that's the finish on it.</div></div><p>Her frame is nine. The number on her line is thirteen. The thing that was holding her shut is older than both.</p><span id="cascade-b2-beat-3"><<linkreplace "Ask how he can tell.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> From the finish.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> From the tooling. Everything's cut a shade wide and then dressed back by hand. That is what you do when you're making eleven of a thing and not eleven thousand.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Let him finish.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And nobody's dressed a part by hand in this city for ten years. Whoever made that had a room, a budget and no hurry.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Ask him to open it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Can you get inside it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> No. Not won't — can't. I cut ships. What's in there wants a clean room and somebody who's seen one before, and there's neither of those within forty miles of this water.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Ask what would.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Paper would.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Your page came open because the two were cut together. That's not a trick I did, that's the same office signing twice. Find me the rest of what that office wrote and I'll have something to work against.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Ask where that lives.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where does an office's paper go.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Not my trade. But paper that's worth anything gets sold, and this city's got exactly one direction it gets sold in, and it isn't up.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Think.">><p>She has met that direction. A careful man in a corner of the Undertow, drinking slow, carrying copies out of Vance Securities and down the strip to somebody who paid on time.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> There was a courier. I never found out who was buying.</div></div><span id="cascade-b2-beat-9"><<linkreplace "Say it out loud.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Then that's your end of it, and it's a better end than mine. A buyer keeps what he buys.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Somebody down there has been collecting that company's paper for years. If your page had a brother, it's in his stack.</div></div><span id="cascade-b2-beat-10"><<linkreplace "Ask if he'll help.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I'll build. That's the arrangement and I've not changed it. You bring me a thing that needs making and I'll price it, and I'll not ask what it's for.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Nothing to say to that.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Two years of being told where to stand and by whom. Nobody has told her to do this. There is no order behind it, no dispatch, no man upstairs waiting on a result. Only a shut page and a hand that closed it, and the fact that she wants to know.</div></div><span id="cascade-b2-beat-12"><<linkreplace "Reach for the chip.">><p>Her hand goes to it and stops. Wherever this goes, it goes through people who put hands in her coat, and there is nothing on her worth less explaining than this.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Keep it on the bench.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It'll be under the jar. It's been under the jar since you left it and the jar's not moved.</div></div><p>She goes up the strip with nothing in her pockets and one question in her. That is more than she has ever carried out of this dock.</p>[[Go and find the buyer.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_chip_read">>
<<set $game_state.current_node = "cap_chip_read.base">>
<<script>>setup.markCanvasTriggered("cap_chip_read");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_chip_read.base") === -1) { vn.push("cap_chip_read.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "chip_read", "set");<</script>><img src="./videos/scenes/mercer_panic.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She comes up to the penthouse with the file to close the job. Finds Mercer on the wrong side of his own desk, a bag open on the glass, feeding paper into a shredder that can't keep up.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It's done. Deep vault, clean pull. Everything you sent me in there for.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Get it away from me. God — do you have any idea what you kicked over? A deep-vault flag with my asset's fingerprints on it, and it is climbing, and it does not stop until it reaches Vance himself.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Watch him unravel.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You wanted this file for a year. Now you won't touch it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> I wanted it when it was a clever little edge. It's a noose now. The Chairman doesn't discipline, he disappears people. I've watched him do it. I will not be standing here when he comes asking who ran an asset into his archive. Keep the file, burn it, I don't care. I need to be gone, and every road out of this tower has his people on it by now.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Offer him the one road he hasn't got.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Not every road. There's one place his people can't follow, because they don't know it's there. Under the docks. Under the Reach. I can walk you into it tonight and nobody topside ever sees where you went.</div></div><p>That stops his hands. He looks at her the way a drowning man looks at a rope he doesn't trust. Because he knows her, knows nothing she offers is free.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> ...And what does that cost me.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Name it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The controller. The one for the governor you had sealed into my core. The little key that decides who I can't turn my teeth on. You've carried it since the day you signed for me. Give it to me and I take you down alive. That's the fare.</div></div><p>For a second the fear thins and something like a smile moves under it. The reflex of a man who's spent his life sure he holds the only card that matters.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> That's it? Take it. It's keyed to me, girl — my hand, my print, it's a dead lump of metal to anyone else alive. You can wear it on a chain. It won't cut a thing.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Take the key. Take him down.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He's wrong, and he'll die never knowing how wrong. Keyed to him, sure. Until a man who takes machines apart for a living gets it under a light. She closes her hand around it and it's the first thing in two years that's hers and about her at once. The file in her coat, the key in her fist. Both locked. Both hers.</div></div><p>She gets him into the car and gives the driver an address that isn't on any manifest. The tower falls away, the city goes lower and wetter, and the Spire seals itself shut behind them. Sweeps on every floor now, her face on every camera at the curb. No ride back up. At the bottom, where the last light gives out, Mercer goes his own way into the dark to find whatever hole a running man finds, and doesn't look back to thank her. The deal's paid; they're quits. She turns the other way, toward the one door down here that owes her nothing and might still help. Kess.</p>[[Down under the city — go to Kess.->Location_underworld_strip]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_1a_close">>
<<set $game_state.current_node = "cap_1a_close.base">>
<<script>>setup.markCanvasTriggered("cap_1a_close");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_1a_close.base") === -1) { vn.push("cap_1a_close.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "archive_1a_done", "set");setup.applyAndNotifyFlag("player", null, "controller_held", "set");<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("company_grays"); setup.equipItem("company_grays");setup.showEffectNotification();<</script>><p>She catches Vane on the back stairs, where the cameras don't reach and Calloway never goes, and doesn't waste the opening on hello.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> A courier at the Undertow gave you up. Not your name — he never had it — your face. Handing him sealed pulls at the loading dock, month after month. Two years Calloway's chased his ghost, and it's been at the next desk the whole time.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> You don't— that's nothing. That's a drunk in a bar, you've got a face and a feeling and no—</div></div><span id="cascade-b1-beat-1"><<linkreplace "Show him the drop.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I've got the courier, the dock, the dates, and a very tired auditor upstairs who'd love a name that isn't Calloway's. I don't want you, Vane. I want one thing out of that vault, and you're cleared for it and I'm not.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> ...Christ. The deep archive? Do you know what they do to— no. I move paper. I don't touch the vault, that's a different—</div></div><span id="cascade-b1-beat-2"><<linkreplace "Make it the only door left.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You pull my file, or the auditor gets your face by morning and it climbs to the Chairman by noon. You know what he does with a leak. My way, you're a man who did a quiet favour. The other way, you're an example.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> ...One file. One. And then I have never met you.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Wait for the file.">><p>It takes him two days and a clearance that isn't his to use. He brings it to the same dead stairwell. A thin sealed folder. His hands aren't steady.</p><span id="cascade-b1-beat-4"><<linkreplace "Take the file.">><p>She has it: the thing Mercer sent her for, and the thing she's wanted in her own hands since she learned it was in this building. A Vance humanoid-program file. About her kind, maybe about her. Light enough to be nothing. She doesn't open it. Not here.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> Don't read it here. And listen — pulling that tripped something. There's a flag on the deep-vault log I can't clear, and somebody's already asking who signed it out.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Ask who's watching.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Calloway's watcher. He never trusted me either.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> Whoever it is, it climbs. And it climbs to the man who ends people for less than this. I'm gone tonight. The Reach, then further. You should be too. What you just did isn't the kind of thing you get to stay for.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> So it's blown. Fine. She has the file and a night's head start, and a man who ends betrayers is now aimed at everyone who touched this. Vane, and the fool up the chain who sent her in. She'd better reach Mercer before the news does.</div></div>[[Get to Mercer.->Location_penthouse]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_vane_blackmail">>
<<set $game_state.current_node = "cap_vane_blackmail.base">>
<<script>>setup.markCanvasTriggered("cap_vane_blackmail");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_vane_blackmail.base") === -1) { vn.push("cap_vane_blackmail.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "docs_retrieved", "set");<</script>><p>She comes back after hours, when the department runs on a skeleton and the floor above is dark. There's Vane, badge on a lanyard, walking the vault door open like it's nothing. The reader goes green for him. A guard nods him through.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Of course. Quiet, tidy, trusted Vane. Senior custody, cleared for the one door that matters, in and out on his own routine while the division dies around him. Whatever she needs out of that vault doesn't come out without a man exactly like him.</div></div>
<<set $game_state.current_canvas = "cap_docs_vane_routine">>
<<set $game_state.current_node = "cap_docs_vane_routine.base">>
<<script>>setup.markCanvasTriggered("cap_docs_vane_routine");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_docs_vane_routine.base") === -1) { vn.push("cap_docs_vane_routine.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Watch him work.->Location_docs_department]]<img src="./videos/scenes/docs_department.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Calloway gave it up under the drain. The deep vault, down here. She comes to see it for herself. The docs department is everything his file room isn't: glass, logged, watched. This is where the files that matter actually live, and where whatever Mercer planted her to fetch is sitting, behind a door with her name nowhere near the list.</p><span id="cascade-b2-beat-0"><p>She badges toward the vault like she belongs there. The reader blinks red. A guard steps half a pace to fill the gap. Not even unfriendly about it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/enns.jpg" alt="Enns" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Enns</strong> That's two-man clearance, love. You're not on the list, and I can't put you on it — nobody at your level goes past me. Anything you need out of the deep archive, you file a pull and someone cleared brings it up.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Ask who's cleared.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And who's cleared?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/enns.jpg" alt="Enns" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Enns</strong> A handful. Senior custody only. They rotate the second man weekly so nobody can walk it out alone. It's the one part of this dying place they still take seriously.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> So there's the wall. Her file is ten feet away behind a door her badge will never open, and the only way through is somebody already on the inside. She'll need one of the cleared few. So she needs to know exactly who they are, and find the right thing to hold over one.</div></div>[[Back out.->Location_docs_department]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_docs_first_look">>
<<set $game_state.current_node = "cap_docs_first_look.base">>
<<script>>setup.markCanvasTriggered("cap_docs_first_look");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_docs_first_look.base") === -1) { vn.push("cap_docs_first_look.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "access_problem_seen", "set");<</script>><p>The whole compartmented, careful little mind of him comes loose down her arm while he's still shaking. Routes and drops and hand-offs, months of them, every pickup he's ever made.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> There. The inside contact. Not a name. Colm was never trusted with a name. A FACE, handing him a sealed packet at a loading dock, month after month. Narrow, nervous, careful. The face she sits three feet from at Calloway's elbow every single day. Vane. It's Vane.</div></div><p>She leaves him face-down and snoring on the empties, his route still spilling out of him into nobody, and walks back up into the night with the one thing she came for. She has the rogue now. She just has to make him hand her the vault.</p>
<<set $game_state.current_canvas = "colm_drain_canvas">>
<<set $game_state.current_node = "colm_drain_canvas.d0">>
<<script>>setup.markCanvasTriggered("colm_drain_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("colm_drain_canvas.d0") === -1) { vn.push("colm_drain_canvas.d0"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Go collect on Vane.->Location_underworld_bar]]<p>The drain fires the way it does now. No discovery left in it, just his Charge coming loose down her arm and the night going soft behind his eyes. He'll wake on the empties grateful and none the wiser, sure he had the best night of his week. In a way he did.</p>
<<set $game_state.current_canvas = "colm_drain_canvas">>
<<set $game_state.current_node = "colm_drain_canvas.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("colm_drain_canvas.done") === -1) { vn.push("colm_drain_canvas.done"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave him to it.->Location_underworld_bar]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<p>He finishes on her face with one hand shaking in her hair, apologising while he does it. Nothing comes loose but him. The drain stays shut. It only opens the one way.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_finish_facial_t5"] to ($game_state.media_cycle["sex_colm_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/colm_finish_facial_t5/c8b2eddc397.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_finish_facial_t5/cab07d5fbd0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_finish_facial_t5/ce6086edb85.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_finish_facial_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<p>He finishes inside her, holding her up against the shelving, breathing like a man who's just been given something. He has been. She hasn't taken anything. Not this way.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_finish_inside_t5"] to ($game_state.media_cycle["sex_colm_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/colm_finish_inside_t5/c5bae15ed64.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_finish_inside_t5/c293c32f790.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_finish_inside_t5/cb853fc000c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_finish_inside_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<p>He finishes in her ass, and the drain opens under it the way it's built to. The shudder cracking him wide, her hand still locked on his forearm, everything he is starting to come loose down her arm.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_finish_anal_t5"] to ($game_state.media_cycle["sex_colm_finish_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_finish_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_finish_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/colm_finish_anal_t5/c1bd134c597.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_finish_anal_t5/c67bb5babaa.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_finish_anal_t5/c79e5de0c9c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_finish_anal_t5/c037160e284.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<</if>>
<<set $game_state.current_canvas = "loop_colm_finisher">>
<<set $game_state.current_node = "loop_colm_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_colm_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_colm_finisher.climax") === -1) { vn.push("loop_colm_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_colm_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Leave him to the empties." "Location_underworld_bar">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_colm_finisher:cc0");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_colm_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Take what he carries." "Canvas_colm_drain_canvas_Node_d0">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "colm_drains_done", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_colm_finisher:cc1");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_colm_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Drink him down again." "Canvas_colm_drain_canvas_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_colm_finisher:cc2");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "gte", "value": 1}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_colm_finisher = [{"text": "Leave him to the empties.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Take what he carries.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "lt", "value": 1}]}}, {"text": "Drink him down again.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "gte", "value": 1}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_colm_finisher",
choices: window._engineNoExitsDiag_loop_colm_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_colm_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_colm_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_false"}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_backroom_t4"] to ($game_state.media_cycle["sex_colm_backroom_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_backroom_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_backroom_t4"]>><<if _mc is 0>><video src="./videos/sex/colm_backroom_t4/c06cf533433.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_backroom_t4/c898bb972fa.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_backroom_t4/ca055246f57.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_backroom_t4/ccbe4fd9c16.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>The back room is empties and stacked cases and one bad bulb. He has her against the shelving before the door's shut. Mouth on her neck, hands going everywhere at once, a careful man with nothing careful left in him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Three weeks I've been telling myself you were being kind. Tell me to stop and I'll stop. Don't, and I won't.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_ruin_t4"] to ($game_state.media_cycle["sex_colm_ruin_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_ruin_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_ruin_t4"]>><<if _mc is 0>><video src="./videos/sex/colm_ruin_t4/c3bcb644ecd.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_ruin_t4/c37d20319b6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_ruin_t4/c2819301d8f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_ruin_t4/cba0df9163a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>The tape gives at the corner and the back room is black behind it and smells of burnt varnish. He has her against what is left of the shelving before the sheet has stopped swinging, mouth at her throat, hands already under her clothes.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Nothing left in here to knock over. Nobody left to walk in on us either. I've thought about that more than I'd care to say out loud.</div></div><p>The bad bulb went with the rest of it. He gets her clothes open in the dark by feel, rough about all of it now, and she does nothing at all to slow his hands down.</p>
<</if>>
<<set $game_state.current_canvas = "loop_colm_backroom">>
<<set $game_state.current_node = "loop_colm_backroom.intro">>
<<script>>setup.markCanvasTriggered("loop_colm_backroom");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_colm_backroom.intro") === -1) { vn.push("loop_colm_backroom.intro"); }<</script>>
<<nobr>>
<<link "Get on your knees." "Canvas_loop_colm_backroom_Node_base_oral_colm">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_loop_oral_t5"] to ($game_state.media_cycle["sex_colm_loop_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_loop_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_loop_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/colm_loop_oral_t5/c2ef1812571.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_loop_oral_t5/c9b02864509.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_loop_oral_t5/c3211d67c7f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_loop_oral_t5/cc475989d63.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees on the concrete with his cock in her mouth, both his hands braced on the case behind him. He watches the door out of thirty years of habit, and loses the habit fast.</p>
<<set $game_state.current_canvas = "loop_colm_backroom">>
<<set $game_state.current_node = "loop_colm_backroom.base_oral_colm">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_colm_backroom.base_oral_colm") === -1) { vn.push("loop_colm_backroom.base_oral_colm"); }<</script>>
<<nobr>>
<<link "Keep him in your mouth." "Canvas_loop_colm_backroom_Node_base_oral_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Stand up and put him in you." "Canvas_loop_colm_backroom_Node_base_vaginal_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_colm_backroom:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_colm_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_colm_backroom:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_loop_vaginal_t5"] to ($game_state.media_cycle["sex_colm_loop_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_loop_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_loop_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/colm_loop_vaginal_t5/c3b4cff62ef.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_loop_vaginal_t5/c7b8c94db63.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_loop_vaginal_t5/c293c32f790.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_loop_vaginal_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She takes him standing, one leg hooked up on a stacked case, his cock working into her cunt while the bar noise comes through the wall. He says her false name into her hair like it's a real one.</p>
<<set $game_state.current_canvas = "loop_colm_backroom">>
<<set $game_state.current_node = "loop_colm_backroom.base_vaginal_colm">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_colm_backroom.base_vaginal_colm") === -1) { vn.push("loop_colm_backroom.base_vaginal_colm"); }<</script>>
<<nobr>>
<<link "Let him have it." "Canvas_loop_colm_backroom_Node_base_vaginal_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_loop_colm_backroom_Node_base_oral_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn around — give him your ass." "Canvas_loop_colm_backroom_Node_base_anal_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_colm_backroom:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_colm_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_colm_backroom:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_colm_loop_anal_t5"] to ($game_state.media_cycle["sex_colm_loop_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_colm_loop_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_colm_loop_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/colm_loop_anal_t5/c7e7b540eff.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/colm_loop_anal_t5/c3748c12b3c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/colm_loop_anal_t5/cb45bddb482.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/colm_loop_anal_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Bent over the stacked cases with his cock in her ass, his hands white-knuckled on her hips. He's forgotten the door, the room, the job. Everything but the fact that she let him.</p><p>She reaches back and gets a hand around his forearm, skin on skin, and holds it there. That's the seat. The drain sits in the contact and waits for the shudder to open it.</p>
<<set $game_state.current_canvas = "loop_colm_backroom">>
<<set $game_state.current_node = "loop_colm_backroom.base_anal_colm">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_colm_backroom.base_anal_colm") === -1) { vn.push("loop_colm_backroom.base_anal_colm"); }<</script>>
<<nobr>>
<<link "Take it in the ass." "Canvas_loop_colm_backroom_Node_base_anal_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on him." "Canvas_loop_colm_backroom_Node_base_vaginal_colm">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_colm_backroom:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — and take what he carries." "Canvas_loop_colm_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_colm_backroom:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_false"}]})>>
<img src="./videos/scenes/colm_after.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Three stools down, in a bar with nothing in it to drink: the man Sol pointed her to. Same corner, same boot hooked through the bag strap, and an empty glass he has not put down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Sol lets me sit. That's the whole arrangement. If you're selling, I'm not buying. I've nothing left to buy with, which saves us both a conversation.</div></div><p>He watches the taped hole in the back wall the way he used to watch the door. She takes the stool beside him. He does not tell her to go.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 24}]})>>
<img src="./videos/scenes/colm_after.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He is here every evening now, in a room that does not open, because it is the only address anybody has for him. A courier who cannot be found is a courier nobody hires.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Man I carried for went out through that wall. Nobody's said his name since. I keep turning up in case somebody wants to start saying it again.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 24}]})>>
<img src="./videos/scenes/colm_after_close.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He is up off the stool before she is fully through the door, hand at her waist, steering her at the dark end of a room nobody has any reason left to walk into.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Used to be I'd wait for Sol's back to turn. There's no bar to be seen at any more. Whole place is the dark end now.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Don't ask me if I'm alright. Ask me anything else you like.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_false"}]})>>
<img src="./videos/scenes/colm_undertow.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Three stools down: the man Sol pointed her to. Corner seat, back to the wall, a bag with a boot hooked through the strap so it never leaves his ankle. He's nursing one drink like it has to last till dawn, and his eyes go to the door on a clock she can't hear. Every ninety seconds, reflex, the tic of a man who's counted the exits in every room he's ever sat in. She takes the stool beside him. He clocks her, weighs her, and gives her exactly nothing. Polite, careful, a man having a quiet one and meaning to keep it that way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> If you're selling, I'm not buying. If you're asking, I'm that even less. Nothing personal. Just how I've stayed a man who gets to keep having quiet ones.</div></div><p>But he doesn't move stools, and he doesn't tell her to leave. He just goes back to watching the door, letting her sit inside the arm's length he gives nobody. That is its own kind of answer. Careful men notice careful people. She hasn't asked him for a single thing; that's the only reason she's still got the seat.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Careful to a fault, exactly like Sol said. Lonely with it, under all that guard. You don't crack a man like this with a question. You crack him with time. The first hour starts with a drink he didn't have to pay for.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 12}]})>>
<img src="./videos/scenes/colm_undertow.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He's still all business, but he lets her take the stool now without the once-over. A careful man testing the shape of her. What she wants, why a woman like her keeps spending her evenings on a courier three seats from the door.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Nobody buys a man this many rounds for the conversation. So what is it. You want something moved, or you want me?</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 12}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 24}]})>>
<img src="./videos/scenes/colm_undertow.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He saves her the stool now. The guard's not gone. A careful man's never fully goes. But he's loose, warm, leaning in to hear her over the room. He watches the door out of habit and her out of want.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> You're the best part of my week, you know that. Whatever it is you actually came for, I'm starting not to care.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 24}]})>>
<img src="./videos/scenes/colm_undertow.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The careful's all the way off him now. He's up off the stool before she's fully in the door, hand at the small of her back, steering her to the dark end of the bar like the room's already theirs. He'll follow her anywhere she points him. She knows exactly where that is.</p>
<</if>>
<<set $game_state.current_canvas = "hub_colm_undertow">>
<<set $game_state.current_node = "hub_colm_undertow.base">>
<<script>>setup.markCanvasTriggered("hub_colm_undertow");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_colm_undertow.base") === -1) { vn.push("hub_colm_undertow.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc0') ? '' : 'unlocked-choice'">
<<link "Can I buy you a drink?" "Canvas_hub_colm_undertow_Node_meet_drink">><<script>>setup.markChoiceVisited("hub_colm_undertow:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc1') ? '' : 'unlocked-choice'">
<<link "Not tonight." "Location_underworld_bar">><<script>>setup.markChoiceVisited("hub_colm_undertow:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc2') ? '' : 'unlocked-choice'">
<<link "Pass the time with him." "Canvas_hub_colm_undertow_Node_talk">><<script>>setup.markChoiceVisited("hub_colm_undertow:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc3') ? '' : 'unlocked-choice'">
<<link "Buy him another." "Canvas_hub_colm_undertow_Node_drink">><<script>>setup.markChoiceVisited("hub_colm_undertow:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 12}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc4') ? '' : 'unlocked-choice'">
<<link "Kiss him." "Canvas_hub_colm_undertow_Node_kiss">><<script>>setup.markChoiceVisited("hub_colm_undertow:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_false"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 24}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc5') ? '' : 'unlocked-choice'">
<<link "Take him in the back." "Canvas_loop_colm_backroom_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_colm_undertow:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "colm_met", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 24}]})>>
<span @class="setup.isChoiceVisited('hub_colm_undertow:cc6') ? '' : 'unlocked-choice'">
<<link "Take him through the tape." "Canvas_loop_colm_backroom_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_colm_undertow:cc6");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave him to his drink." "Location_underworld_bar">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She flags Sol for two and slides one in front of him before he can wave it off. Colm looks at the glass, looks at her, and does the arithmetic of a man who trusts nothing free. What it costs him to drink it against what it costs him to refuse. Refusing is the louder tell. He drinks.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> ...Appreciated. Doesn't buy you anything but the drink, understand. But — appreciated.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> No sell, no ask. Just the only man in here who looks like he'd still be alive this time next year. And I'm tired of drinking alone.</div></div><p>That earns her a look, a real one, held a beat longer than he means to give it. Two careful people clocking the same wariness in each other. He says nothing else worth keeping. But he lets a whole minute pass without checking the door, and for a man like Colm that's most of a confession.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> One drink in and he's still all edges. Fine. She's got nowhere to be and he's here every night. Somewhere under the careful there's a courier who moves things between the worlds for a buyer who pays on time. That's the thread. She just has to be patient enough to pull it, a round at a time.</div></div>
<<set $game_state.current_canvas = "hub_colm_undertow">>
<<set $game_state.current_node = "hub_colm_undertow.meet_drink">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_colm_undertow.meet_drink") === -1) { vn.push("hub_colm_undertow.meet_drink"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_colm", "relation", "add", 3.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "colm_met", "set");<</script>>
[[Let him nurse it. Come back.->Location_underworld_bar]]<<set _bp to random(0, 2)>>
<<if _bp is 0>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> You want to know how you last down here? You never carry what you can't drop and you never learn a name you don't need. I've forgotten more people than this bar's seen. On purpose.</div></div>
<<elseif _bp is 1>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Buyer up top pays on time, never asks how, never says thanks. Best kind of work there is. The kind nobody wants to be caught talking about, me included. So we won't.</div></div>
<<else>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Sol vouches for exactly nobody, and he lets you sit here. That's the only reference in this room worth a damn, and it's the only reason I haven't moved stools.</div></div>
<</if>><p>He talks around the work, never through it. But he talks, which for Colm is a door coming open a finger's width at a time. Each hour she spends not asking him for anything is an hour he trusts her a little more.</p>
<<set $game_state.current_canvas = "hub_colm_undertow">>
<<set $game_state.current_node = "hub_colm_undertow.talk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_colm_undertow.talk") === -1) { vn.push("hub_colm_undertow.talk"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_colm", "relation", "add", 2.0, false, null);setup.showEffectNotification();<</script>>
[[Let it ride.->Location_underworld_bar]]<p>Another round, and the night wears on the way nights do down here. Slow, red-lit, the room thinning around them. He drinks careful, always careful. But he drinks with her now, which for a man who's made a life of drinking alone is not nothing.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 12}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> I don't get sloppy — never have, not the job for it. But I'll drink what you're pouring. Beats the wall, and you don't talk half as much as the others who try to sit here.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 12}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 24}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> You're turning into a habit. Only good kind there is, in my line. The sort nobody's supposed to know I've got. Don't make me regret it.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 24}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> Keep buying and I keep forgetting to watch that door. Reckon you know that. Reckon that's the point. And I've stopped minding either way.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_colm_undertow">>
<<set $game_state.current_node = "hub_colm_undertow.drink">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_colm_undertow.drink") === -1) { vn.push("hub_colm_undertow.drink"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_colm", "relation", "add", 3.0, false, null);setup.showEffectNotification();<</script>>
[[One more, then.->Location_underworld_bar]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 16}]})>>
<p>She leans in and kisses him, slow, in the middle of the crowded bar. He goes stiff. A careful man's whole body saying not here, not smart, not safe. He pulls back an inch before he lets himself have even a second of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> —not here. People see. You don't know who drinks in this room.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 16}, {"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "lt", "value": 20}]})>>
<p>This time he doesn't pull back as far. His hand comes up to her jaw like it decided on its own, and the careful takes a beat longer to win. He's warming. She can feel exactly where the guard thins.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/colm.jpg" alt="Colm" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Colm</strong> You're going to get me killed. ...Do it again.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_colm", "trait_key": "relation", "operator": "gte", "value": 20}]})>>
<p>Now he stops flinching entirely. He kisses her back like the room isn't there, one hand fisted in her coat, the careful drinker gone under a want he isn't managing anymore.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> There. The guard's off. One more lean and he'll follow her anywhere she points him. Including the back, where the drain likes to work.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_colm_undertow">>
<<set $game_state.current_node = "hub_colm_undertow.kiss">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_colm_undertow.kiss") === -1) { vn.push("hub_colm_undertow.kiss"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_colm", "relation", "add", 4.0, false, null);setup.showEffectNotification();<</script>>
[[Let him breathe.->Location_underworld_bar]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_false"}]})>>
<img src="./videos/scenes/underworld_bar_bartender.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Sol works the taps at the dim end of the bar, wiping a glass that's already clean. He's outlasted every owner this place has had. It's had a few, though the one it answers to now never shows his face. He hears everything said over his counter down here and repeats none of it, unless you're the kind he's decided he likes. He's decided he likes her. Mostly.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}]})>>
<img src="./videos/scenes/underworld_bar_after.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The taps are dry and the counter is under a sheet. Sol works along the back wall with a shovel and a bucket, moving burned timber from one side of the room to the other side of the room.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Place has had owners. Had a few. That's the first one who got took instead of bought out, and I find I've got no idea what a man does about it.</div></div><p>He does not ask where she was that night. She does not tell him. He has outlasted every owner this bar has had, and this is the first time it has left him with nothing to do.</p>
<</if>>
<<set $game_state.current_canvas = "hub_sol_undertow">>
<<set $game_state.current_node = "hub_sol_undertow.base">>
<<script>>setup.markCanvasTriggered("hub_sol_undertow");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sol_undertow.base") === -1) { vn.push("hub_sol_undertow.base"); }<</script>>
<<nobr>>
<<link "Pass a word with Sol." "Canvas_hub_sol_undertow_Node_talk">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "raid_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "bastien_no_body", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_sol_undertow:cc0') ? '' : 'unlocked-choice'">
<<link "Ask what they did with Bastien." "Canvas_hub_sol_undertow_Node_bastien">><<script>>setup.markChoiceVisited("hub_sol_undertow:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "pipe_known", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "colm_found", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_sol_undertow:cc1') ? '' : 'unlocked-choice'">
<<link "Ask who moves things between the worlds." "Canvas_hub_sol_undertow_Node_carrier">><<script>>setup.markChoiceVisited("hub_sol_undertow:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "names_known", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "hunt_lead", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_sol_undertow:cc2') ? '' : 'unlocked-choice'">
<<link "Ask him about Doss and Rourke." "Canvas_hub_sol_undertow_Node_crew">><<script>>setup.markChoiceVisited("hub_sol_undertow:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Nothing tonight." "Location_underworld_bar">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<set _bp to random(0, 2)>>
<<if _bp is 0>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Rule of the Undertow: down here nobody's who they were up there. Man walks in, whatever he did in the daylight stays at the door. Keeps the peace. Keeps my bar standing.</div></div>
<<elseif _bp is 1>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Bar's owned by somebody now who never comes down to look at it. Suits me. An owner you never see is an owner who never asks questions you can't answer.</div></div>
<<else>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> You want to last down here, you learn what I learned: hear it all, hold it all, hand out none of it for free. That's not being cold. That's the rent.</div></div>
<</if>><p>He talks the way a man talks who's decided you're all right. Not warm, exactly, but no longer watching his own mouth. Down here that's most of the way to a friend.</p>
<<set $game_state.current_canvas = "hub_sol_undertow">>
<<set $game_state.current_node = "hub_sol_undertow.talk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sol_undertow.talk") === -1) { vn.push("hub_sol_undertow.talk"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Let him work.->Location_underworld_bar]]<p>She asks it over the noise of the shovel and does not dress it up, and Sol does not stop working while he answers her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Company came through on the third day with a clipboard and two men in masks, and they wrote down everything that was in this building. Took them four hours. Chair, floor, half a wall, the taps, forty years of somebody else being here before him.</div></div><p>He works another load of burned timber into the bucket and sets it down where the end of the counter used to be.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> I asked the one with the clipboard what I was supposed to do about a service. He looked down the list and told me there was nothing on it to have a service over. Eleven years I worked for that man and there is not a thing to put in the ground, and I have stopped asking about it, because the asking was getting to be the whole of my day.</div></div><p>She tells him she is sorry and it is even true, and he nods at the wall and goes back to the timber. She has somewhere to be and she goes there.</p>
<<set $game_state.current_canvas = "hub_sol_undertow">>
<<set $game_state.current_node = "hub_sol_undertow.bastien">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sol_undertow.bastien") === -1) { vn.push("hub_sol_undertow.bastien"); }<</script>>
<<script>>advanceTime(15);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "bastien_no_body", "set");<</script>>
[[Let him work.->Location_underworld_bar]]<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I need a carrier. Somebody who moves freight both ways — outer world to under, under to outer — and never leaves it on paper. Company work, the kind that never happened.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Short list down here, and a shorter one that's any good. The one you want's called Colm. Runs sealed packets for a buyer who pays too well to name, and hasn't let a thing show up in a ledger in all the years I've watched him drink. Careful to a fault.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where do I find him.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Right here, most nights — corner stool, back to the wall, drinking slow so he stays sharp. In around seven, nurses it till close. Buy the man a drink. He warms slower than he'll ever admit, but he warms.</div></div><p>A name, a stool, a habit. The whole of it. She looks down the bar and finds him without trying: a wary regular three stools down, a bag with a boot hooked through the strap, eyes on the door out of pure reflex. Her thread up out of Calloway's file room and straight to whoever's buying.</p>
<<set $game_state.current_canvas = "hub_sol_undertow">>
<<set $game_state.current_node = "hub_sol_undertow.carrier">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sol_undertow.carrier") === -1) { vn.push("hub_sol_undertow.carrier"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "colm_found", "set");<</script>>
[[Colm, then.->Location_underworld_bar]]<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Two men. Doss and Rourke. They came up out of the underworld before they ever ran for Renner. You'd have known them.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> Doss I knew. Ran cargo for the company back when it still pretended it didn't. Renner made an example of him — him and Rourke both, and it took. But Doss ran with a third. A fixer, name of Marsh. Careful little man, and still breathing.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sol.jpg" alt="Sol" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sol</strong> He keeps one habit. The House, every Sunday — same girl, like clockwork. That's the only place Marsh surfaces. A man with one habit's got one weakness.</div></div><p>He sets the clean glass down. A name, a day, a door. The whole of it. Then, not looking up: "Whatever you carry that does your quiet work — carry it Sunday. Marsh doesn't talk twice."</p>
<<set $game_state.current_canvas = "hub_sol_undertow">>
<<set $game_state.current_node = "hub_sol_undertow.crew">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_sol_undertow.crew") === -1) { vn.push("hub_sol_undertow.crew"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "hunt_lead", "set");<</script>>
[[Sundays, then. Carry the drain.->Location_underworld_bar]]<p>The drain opens all the way and she takes him properly. Not a skim, the whole live current of him coming loose through the contact. His Charge, his week, the last hour, going soft and white while she holds the pull steady and drinks it down.</p><p>And while he's this open, this undefended, she asks him the one thing she came for: where a company that never loses a page keeps what it can't afford to lose. He gives it up without knowing he's giving it. The deep vault, down in the docs department, the sealed archive nobody at her level ever badges into. Whatever Mercer planted her to fetch is sitting behind that door.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> So now she has the where, and a leash on the man who gave it to her. She can open him whenever the drain's hungry and he'll thank her for it; he'll never remember telling her a thing. Easier to keep him than to open that vault. That part she'll have to solve herself.</div></div><p>He blinks, the minutes wiped, disoriented in his own chair. 'Sorry. Lost the thread. Where were we.' She tells him it's nothing. Drink some water.</p>
<<set $game_state.current_canvas = "calloway_drain_canvas">>
<<set $game_state.current_node = "calloway_drain_canvas.d0">>
<<script>>setup.markCanvasTriggered("calloway_drain_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("calloway_drain_canvas.d0") === -1) { vn.push("calloway_drain_canvas.d0"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Straighten up.->Location_vance_securities]]<p>The drain fires the way it always does now. No drama, no discovery, just his Charge coming loose into her and the minutes going with it. He surfaces grateful and none the wiser, his hand finding hers like it's the only true thing in the room. She lets him think it is.</p>
<<set $game_state.current_canvas = "calloway_drain_canvas">>
<<set $game_state.current_node = "calloway_drain_canvas.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("calloway_drain_canvas.done") === -1) { vn.push("calloway_drain_canvas.done"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave him to it.->Location_vance_securities]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<p>He finishes on her face with a sound that's half relief, one hand cradling her head like she's the first good thing in two years. He'd give her anything now. He doesn't know what she's about to take.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_finish_facial_t5"] to ($game_state.media_cycle["sex_calloway_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_calloway_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_finish_facial_t5/c68f4bb2d43.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_finish_facial_t5/c244b433321.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/calloway_finish_facial_t5/c66861dfacf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_finish_facial_t5/cd0cc7eb194.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<p>He finishes inside her, holding her down on him, shaking, and after he just breathes into her neck. Wrecked, grateful, believed. She lets him have it. Letting him have it is how she keeps him.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_finish_inside_t5"] to ($game_state.media_cycle["sex_calloway_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_calloway_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_finish_inside_t5/c10e9049798.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_finish_inside_t5/cc5df6e2942.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/calloway_finish_inside_t5/cc7cdae36aa.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_finish_inside_t5/ccae08a5789.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<p>He finishes in her ass, and the drain opens under it the way it's built to. His whole self coming loose through the contact, the last few minutes already going soft and white behind his eyes.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_finish_anal_t5"] to ($game_state.media_cycle["sex_calloway_finish_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_finish_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_calloway_finish_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_finish_anal_t5/c22e6b78ef7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_finish_anal_t5/c79e5de0c9c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/calloway_finish_anal_t5/c037160e284.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_finish_anal_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<</if>>
<<set $game_state.current_canvas = "loop_calloway_finisher">>
<<set $game_state.current_node = "loop_calloway_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_calloway_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_calloway_finisher.climax") === -1) { vn.push("loop_calloway_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_calloway_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Straighten up." "Location_vance_securities">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_calloway_finisher:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_calloway_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Open the drain on him." "Canvas_calloway_drain_canvas_Node_d0">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "calloway_drains_done", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_calloway_finisher:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_calloway_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Take him again." "Canvas_calloway_drain_canvas_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_calloway_finisher:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "gte", "value": 1}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_calloway_finisher = [{"text": "Straighten up.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Open the drain on him.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]}}, {"text": "Take him again.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "gte", "value": 1}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_calloway_finisher",
choices: window._engineNoExitsDiag_loop_calloway_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_calloway_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_calloway_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_loop_t5"] to ($game_state.media_cycle["sex_calloway_loop_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_loop_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_calloway_loop_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_loop_t5/c3fc6d131a1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_loop_t5/c8f262a391c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/calloway_loop_t5/ca6a0a04daa.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_loop_t5/cd18272086e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She shuts the file-room door for the last time as an analyst. He's already got his hands in her hair. The disbelieved man gone, just someone who's decided to trust the one person who ever let him.</p>
<<set $game_state.current_canvas = "loop_calloway_sex">>
<<set $game_state.current_node = "loop_calloway_sex.intro">>
<<script>>setup.markCanvasTriggered("loop_calloway_sex");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_calloway_sex.intro") === -1) { vn.push("loop_calloway_sex.intro"); }<</script>>
<<nobr>>
<<link "Get on your knees." "Canvas_loop_calloway_sex_Node_base_oral_c">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_loop_oral_t5"] to ($game_state.media_cycle["sex_calloway_loop_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_loop_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_calloway_loop_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_loop_oral_t5/c5284915299.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_loop_oral_t5/c9364663438.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/calloway_loop_oral_t5/cea1b77fc56.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_loop_oral_t5/cf29cbd1247.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees with his cock in her mouth, and even now he half-talks. The ghost, the case, the shape of the thing he's chased for two years. The work is the only place he's ever felt safe, and she's made herself the second.</p>
<<set $game_state.current_canvas = "loop_calloway_sex">>
<<set $game_state.current_node = "loop_calloway_sex.base_oral_c">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_calloway_sex.base_oral_c") === -1) { vn.push("loop_calloway_sex.base_oral_c"); }<</script>>
<<nobr>>
<<link "Keep him in your mouth." "Canvas_loop_calloway_sex_Node_base_oral_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Climb on." "Canvas_loop_calloway_sex_Node_base_vaginal_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_calloway_sex:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_calloway_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_calloway_sex:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_loop_vaginal_t5"] to ($game_state.media_cycle["sex_calloway_loop_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_loop_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_calloway_loop_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_loop_vaginal_t5/c1e99326e8e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_loop_vaginal_t5/c17c708b624.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/calloway_loop_vaginal_t5/ce2766d3dab.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_loop_vaginal_t5/cfb743a44e0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She rides him in the desk chair, slow, and he holds her face in both hands like he's checking she's real. He tells her the true name of the rogue he's chasing. She files it. She files everything.</p>
<<set $game_state.current_canvas = "loop_calloway_sex">>
<<set $game_state.current_node = "loop_calloway_sex.base_vaginal_c">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_calloway_sex.base_vaginal_c") === -1) { vn.push("loop_calloway_sex.base_vaginal_c"); }<</script>>
<<nobr>>
<<link "Take him." "Canvas_loop_calloway_sex_Node_base_vaginal_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on him." "Canvas_loop_calloway_sex_Node_base_oral_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn around — give him your ass." "Canvas_loop_calloway_sex_Node_base_anal_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_calloway_sex:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_calloway_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_calloway_sex:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_calloway_loop_anal_t5"] to ($game_state.media_cycle["sex_calloway_loop_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_calloway_loop_anal_t5"] + 1) % 3)>><<set _mc to $game_state.media_cycle["sex_calloway_loop_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/calloway_loop_anal_t5/c871b89f398.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/calloway_loop_anal_t5/c4123b1cad3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/calloway_loop_anal_t5/c908064aa8b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Bent over the desk he's guarded for two years, his cock in her ass, both his hands gripping like she's the last solid thing in a building that's been cutting him loose. This is the act that opens the drain. The one place her power still works freely, on a man who isn't the one who owns her.</p>
<<set $game_state.current_canvas = "loop_calloway_sex">>
<<set $game_state.current_node = "loop_calloway_sex.base_anal_c">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_calloway_sex.base_anal_c") === -1) { vn.push("loop_calloway_sex.base_anal_c"); }<</script>>
<<nobr>>
<<link "Take it in the ass." "Canvas_loop_calloway_sex_Node_base_anal_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on him." "Canvas_loop_calloway_sex_Node_base_vaginal_c">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_calloway_sex:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish — and take what he knows." "Canvas_loop_calloway_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_calloway_sex:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><img src="./videos/scenes/calloway_flinch.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He stops her hand mid-reach and holds it. Not gentle.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> Why you. Why now. Nobody in this building has been decent to me in two years and then you walk in and you're this. What do you actually want. Who sent you.</div></div><p>It's the closest he's come to the truth, and he doesn't even know it.</p><span id="cascade-b2-beat-1"><<linkreplace "Re-anchor him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You've been right for two years, and alone for two years. I'm not here to make you alone. I'm here because you're the only one who was ever right.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> ...God. I want that to be true.</div></div><p>He lets her hand go, and keeps it. The suspicion doesn't leave him. It just stops winning.</p>[[Let him have it.->Location_vance_securities]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_calloway_flinch">>
<<set $game_state.current_node = "cap_calloway_flinch.base">>
<<script>>setup.markCanvasTriggered("cap_calloway_flinch");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_calloway_flinch.base") === -1) { vn.push("cap_calloway_flinch.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "calloway_flinch_resolved", "set");<</script>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_calloway_oral_t5"] to ($game_state.media_cycle["scenes_rung_calloway_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_calloway_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_calloway_oral_t5"]>><<if _mc is 0>><video src="./videos/scenes/rung_calloway_oral_t5/c0b7ba5d6ec.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_calloway_oral_t5/c70f234c18c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_calloway_oral_t5/c5289fb9d1d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_calloway_oral_t5/ce3f958f196.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She takes him out from behind the desk and puts her mouth on him, and the sound he makes isn't lust. It's relief, like something clenched for two years finally letting go.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "lt", "value": 12}]})>>
<p>He tries to stay in his head. Keeps talking, the case, the ghost, the names, even with his cock in her throat, because the work is the only place he's ever been safe. She lets him. She's good at making a man feel safe while she takes him apart.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "gte", "value": 12}]})>>
<p>Now he doesn't talk. He holds the back of her head, not pushing, just needing to know she's real, and she lets him fill her mouth and swallows it and calls it access.</p>
<</if>>
<<set $game_state.current_canvas = "rung_calloway_oral">>
<<set $game_state.current_node = "rung_calloway_oral.base">>
<<script>>setup.markCanvasTriggered("rung_calloway_oral");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_calloway_oral.base") === -1) { vn.push("rung_calloway_oral.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
[[Wipe your mouth. Go.->Location_vance_securities]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_calloway_contact_t4"] to ($game_state.media_cycle["scenes_rung_calloway_contact_t4"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_calloway_contact_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_calloway_contact_t4"]>><<if _mc is 0>><video src="./videos/scenes/rung_calloway_contact_t4/c6d1c6dde0f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_calloway_contact_t4/c8a588fb7d3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_calloway_contact_t4/ce3dc2eca8b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_calloway_contact_t4/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>The file room, late. He's stopped pretending to work; she's stopped pretending to file. When she puts a hand flat on his chest he goes still.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "lt", "value": 6}]})>>
<p>Not the still of a man being seduced. The still of a man who's forgotten what it is to be touched by someone who isn't about to take something from him. She is, of course. He just doesn't know it yet.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> ...What are you doing.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "gte", "value": 6}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> You don't have to do this part. Whatever he's paying you to get out of me. Not this part.</div></div><p>He says it like a man hoping to be argued with. She doesn't argue. She just doesn't stop, and he lets her not stop.</p>
<</if>>
<<set $game_state.current_canvas = "rung_calloway_contact">>
<<set $game_state.current_node = "rung_calloway_contact.base">>
<<script>>setup.markCanvasTriggered("rung_calloway_contact");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_calloway_contact.base") === -1) { vn.push("rung_calloway_contact.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
[[Leave it there for tonight.->Location_vance_securities]]<p>With the sealed side of the hunt open to her now, she can finally see the far end. The far end is a place Calloway has never once been.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> The pulls don't get sold up here. They go DOWN. Into the Reach, through the kind of courier who never touches a ledger and never shows on a manifest. A company man could audit this room ten more years and never find him, because he isn't in any record there is. But she knows that world. She knows who to ask. Down at the Undertow, Sol has poured for every carrier who ever worked the Reach; he'll know the man who runs this.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> I'll re-run the logistics side tomorrow. There's something in the courier contracts I keep missing. I can feel it.</div></div><p>She tells him that sounds right, and lets him keep chasing the ghost through paper. She already knows where she's going tonight: the Undertow, to put Sol's word to the man who carries it.</p>
<<set $game_state.current_canvas = "cap_case_pipe">>
<<set $game_state.current_node = "cap_case_pipe.base">>
<<script>>setup.markCanvasTriggered("cap_case_pipe");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_case_pipe.base") === -1) { vn.push("cap_case_pipe.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "pipe_known", "set");<</script>>
[[Head for the Reach.->Location_vance_securities]]<p>She stops chasing the leaks and starts reading the hunt itself. His two years of dead ends. And the dead ends have a pattern he's too close to see.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> The vendors, the couriers, the temp staff. I ran all of it. Ran my own people first, God help me, and they came back solid. Every thread just goes cold on me.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Every thread goes cold because the same hand keeps it cold. One of the few he trusts has been steering him off it for two years. Vetting the lead that mattered, losing the record that pointed home. It's someone on his own team. She doesn't say it. The day she says it he's finished, and so is her way in.</div></div>
<<set $game_state.current_canvas = "cap_case_curated">>
<<set $game_state.current_node = "cap_case_curated.base">>
<<script>>setup.markCanvasTriggered("cap_case_curated");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_case_curated.base") === -1) { vn.push("cap_case_curated.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "case_curated_seen", "set");<</script>>
[[Say nothing. Keep going.->Location_vance_securities]]<p>A week of pulling boxes with him and the shape starts to show. She lays three of the leaked pulls side by side on his desk and taps them.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> No forced drawer. No missing page. Every one of these was clean, and every one was exactly worth taking. Nobody broke in, Calloway. Somebody walked it out the front door.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> ...An inside job. Two years I've said it and the audit calls me paranoid because there's never a mark. You put it on my desk in ten days.</div></div>
<<set $game_state.current_canvas = "cap_case_insider">>
<<set $game_state.current_node = "cap_case_insider.base">>
<<script>>setup.markCanvasTriggered("cap_case_insider");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_case_insider.base") === -1) { vn.push("cap_case_insider.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "case_insider_seen", "set");<</script>>
[[Keep digging.->Location_vance_securities]]<img src="./videos/scenes/calloway_access.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She's in the room enough now that he talks while he works. Tonight he stops working, and just looks at her like he's deciding something.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> Two years I've run this alone because nobody believed there was anything to run. You do. So I'm going to show you the part I don't show anyone. The pulls I never logged, the names I couldn't prove.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Show me all of it.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Take the keys.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> ...God, it's good to not be the only one anymore. Here. This is everything. Don't make me regret it.</div></div><p>He hands her the real access: the sealed side of the hunt, the run of it he's kept off every desk but his own. She's all the way in now. Exactly where she needs to be.</p>[[Take it all.->Location_vance_securities]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_calloway_access">>
<<set $game_state.current_node = "cap_calloway_access.base">>
<<script>>setup.markCanvasTriggered("cap_calloway_access");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_calloway_access.base") === -1) { vn.push("cap_calloway_access.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "calloway_believes", "set");<</script>><p>A leaving card goes round in a manila envelope. Third one this month. She signs under a dozen names she doesn't know, for a woman she's never met, packing a plant and a decade into one copier-paper box. Nobody's planning a party. There's nowhere left to have it.</p>
<<set $game_state.current_canvas = "amb_floor_goodbye">>
<<set $game_state.current_node = "amb_floor_goodbye.base">>
<<script>>setup.markCanvasTriggered("amb_floor_goodbye");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("amb_floor_goodbye.base") === -1) { vn.push("amb_floor_goodbye.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Pass it on.->Location_vance_securities]]<p>Two auditors in good suits are sealing the old records office with tamper tape and a printed inventory, working right past a name plate nobody's taken down. They don't look at her. To them the whole division is already a line item that closes Friday.</p>
<<set $game_state.current_canvas = "amb_floor_audit">>
<<set $game_state.current_node = "amb_floor_audit.base">>
<<script>>setup.markCanvasTriggered("amb_floor_audit");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("amb_floor_audit.base") === -1) { vn.push("amb_floor_audit.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Walk past.->Location_vance_securities]]<p>The lights over the far half of the floor have been off a week. Nobody filed the ticket. A dead colleague's monitor still cycles a screensaver over a chair that isn't coming back, and the building keeps the heat on out of habit. It's very quiet in here for a place that's supposed to be working.</p>
<<set $game_state.current_canvas = "amb_floor_dying">>
<<set $game_state.current_node = "amb_floor_dying.base">>
<<script>>setup.markCanvasTriggered("amb_floor_dying");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("amb_floor_dying.base") === -1) { vn.push("amb_floor_dying.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Get back to it.->Location_vance_securities]]<p>She comes onto the floor out of the kit, back in her own sharp line, and Calloway catches it before she's three steps in. He knows her. That's not the problem. The problem is everyone else who knows a junior analyst doesn't dress like that.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> What are you doing up here looking like that. You want the audit asking who the analyst in the good coat is? Go. Change. Come back nobody.</div></div><p>He's right and they both know it. Nothing she needs off this floor happens while she's wearing the wrong face. The kit's back on the rack in her quarters.</p>
<<set $game_state.current_canvas = "react_calloway_nocover">>
<<set $game_state.current_node = "react_calloway_nocover.base">>
<<script>>setup.markCanvasTriggered("react_calloway_nocover");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_calloway_nocover.base") === -1) { vn.push("react_calloway_nocover.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Go change.->Location_vance_securities]]<img src="./videos/scenes/archive_cover.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She comes onto the Vance floor in her own face. The sharp company line, not the plain kit. It lands wrong the second the light finds her. A junior analyst doesn't dress like she's worth more than the floor she's standing on. A head comes up. On a division being audited, a turned head is how a question starts.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Wrong skin for this floor. Nothing gets done looking like this. The kit's on the rack up in her quarters. Where it does her no good.</div></div>
<<set $game_state.current_canvas = "react_calloway_precover">>
<<set $game_state.current_node = "react_calloway_precover.base">>
<<script>>setup.markCanvasTriggered("react_calloway_precover");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_calloway_precover.base") === -1) { vn.push("react_calloway_precover.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("cover_analyst");setup.showEffectNotification();<</script>>
[[Back out before it's a question.->Location_spire_plaza]]<p>Vane's at the coffee machine, waiting out a slow drip, easy the way the other three never quite manage. He makes room for her unasked.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> Don't let Reyes get to you. She's right that it's over and wrong about how to leave. You do the job clean to the last day. That's the one thing they can't take back. Calloway taught me that, funnily enough.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You believe him? The leak?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/vane.jpg" alt="Vane" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Vane</strong> I believe there's always something moving that shouldn't be. Whether he ever gets his hands on it...</div></div><p>He shrugs, easy, and takes his coffee back to a desk tidier than anyone else's on a floor that's dying. The most trustworthy man in the room.</p>
<<set $game_state.current_canvas = "walkin_chat_vane">>
<<set $game_state.current_node = "walkin_chat_vane.base">>
<<script>>setup.markCanvasTriggered("walkin_chat_vane");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("walkin_chat_vane.base") === -1) { vn.push("walkin_chat_vane.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Let him get back to it.->Location_vance_securities]]<p>Marr's got the crossword folded to a quarter and a pen he isn't using. He raises it in a lazy salute.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/marr.jpg" alt="Marr" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Marr</strong> The dream team. A woman who actually reads the files, a boss who believes in monsters, and me. You know the shredder's run more hours this month than the three of us combined? That's the real audit finding. Nobody writes it down.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You could help him.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/marr.jpg" alt="Marr" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Marr</strong> I could. Six letters for 'why bother.'</div></div>
<<set $game_state.current_canvas = "walkin_chat_marr">>
<<set $game_state.current_node = "walkin_chat_marr.base">>
<<script>>setup.markCanvasTriggered("walkin_chat_marr");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("walkin_chat_marr.base") === -1) { vn.push("walkin_chat_marr.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Leave him his crossword.->Location_vance_securities]]<p>Reyes has her jacket on at her desk, phone face-up, one eye on the door out.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/reyes.jpg" alt="Reyes" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Reyes</strong> Advice, since you're new and nobody else will: don't get pulled into the ghost story. There's no rogue. There's a sad man who missed his window and needs the leak to be real so the last two years meant something. I'm gone Friday. You should be looking too.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And if the leak's real?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/reyes.jpg" alt="Reyes" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Reyes</strong> Then it's above our clearance and someone else's problem. Same difference to us.</div></div>
<<set $game_state.current_canvas = "walkin_chat_reyes">>
<<set $game_state.current_node = "walkin_chat_reyes.base">>
<<script>>setup.markCanvasTriggered("walkin_chat_reyes");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("walkin_chat_reyes.base") === -1) { vn.push("walkin_chat_reyes.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Let her watch the door.->Location_vance_securities]]<p>Voss is taping a box shut at the desk he's had since before she was built. He doesn't stop for her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/voss.jpg" alt="Voss" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Voss</strong> Thirty-one years. They give you a badge and a mug and tell you it means something, and one Tuesday a kid with a clipboard decides the whole floor's a rounding error. Calloway's the only one who ever gave a damn what was in these boxes.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> He still does.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/voss.jpg" alt="Voss" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Voss</strong> That's the tragedy of him, isn't it.</div></div>
<<set $game_state.current_canvas = "walkin_chat_voss">>
<<set $game_state.current_node = "walkin_chat_voss.base">>
<<script>>setup.markCanvasTriggered("walkin_chat_voss");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("walkin_chat_voss.base") === -1) { vn.push("walkin_chat_voss.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Leave him to his boxes.->Location_vance_securities]]<<set _sub_target = setup.checkAndSubstituteCanvas("chat_the_floor")>><<if _sub_target>><<goto _sub_target>><</if>>
<p>She takes a lap of the floor with a coffee she won't drink. The analyst's oldest cover, looking busy going nowhere. Half the desks are boxed up. The other half pretend the audit isn't three feet away.</p>
<<set $game_state.current_canvas = "chat_the_floor">>
<<set $game_state.current_node = "chat_the_floor.base">>
<<script>>setup.markCanvasTriggered("chat_the_floor");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("chat_the_floor.base") === -1) { vn.push("chat_the_floor.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Back to it.->Location_vance_securities]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]})>>
<p>She pulls a box he hasn't reached and starts cross-referencing the dates against the pulls he's flagged. The actual work, the part every other minder skipped straight past on the way to the close order.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> You're... actually reading them. Huh. Left column's the ones that went missing clean. Right's the ones somebody dressed up after. Don't mix them or I lose a week.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then I won't mix them.</div></div><p>He goes quiet and works beside her. Not warming to her, exactly. Warming to not being alone in it.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "gte", "value": 1}]})>>
<p>She works the boxes beside him the same as before. Except it's cover now, not courtship. He believes every inch of her; she's the one who decides what the case turns up, and when.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> Left column clean, right column dressed. You know the drill by now. Don't know what I did before you.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Nothing. He did nothing before her and he'll remember nothing after. She logs another hour at the desk of a man who's already hers.</div></div>
<</if>><p>She squares the pulled boxes back into the row and marks the hour on his sheet.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "case_insider_seen", "operator": "is_false"}]})>>
<p>Dates, pull-slips, signatures. The boxes stay boxes. Whatever's in here is in the pattern and not the pages. The pattern needs more of them open than she's got open.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "case_insider_seen", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "case_curated_seen", "operator": "is_false"}]})>>
<p>She has the how now: nobody broke in. What she doesn't have is whose hand. That's in his two years of dead ends, not in the thefts. There are a lot of dead ends left to read.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "case_curated_seen", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "calloway_believes", "operator": "is_false"}]})>>
<p>The trail runs into the part of the hunt he keeps sealed, and no box on this floor opens that. He does. When he decides she's worth handing it to.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "case_curated_seen", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "calloway_believes", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "pipe_known", "operator": "is_false"}]})>>
<p>The sealed side is hers now and the far end is close. A pass or two more through the logistics. The contracts, the manifests that don't match. Then she'll have where it goes.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "pipe_known", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "lt", "value": 1}]})>>
<p>The paper's finished. It gave up the how and it gave up where, and it will never give up a name. The man carrying it was never written down. That answer's down in the underworld, at the Undertow, not in this room.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "colm_drains_done", "operator": "gte", "value": 1}]})>>
<p>She has the rogue, and he's two desks away. Nothing in these boxes confirmed it and nothing in them ever will. What's left isn't filing. It's Vane.</p>
<</if>>
<<set $game_state.current_canvas = "work_the_case">>
<<set $game_state.current_node = "work_the_case.base">>
<<script>>setup.markCanvasTriggered("work_the_case");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("work_the_case.base") === -1) { vn.push("work_the_case.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_calloway", "relation", "add", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "case_progress", "add", 1.0, false, null);setup.showEffectNotification();<</script>>
[[Log the hour.->Location_vance_securities]]<<set _sub_target = setup.checkAndSubstituteCanvas("hub_calloway_fileroom")>><<if _sub_target>><<goto _sub_target>><</if>>
<img src="./videos/scenes/calloway_fileroom.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Calloway's file room. Boxes to the ceiling, an index on none of them, a man who knows where everything is and trusts no one else to touch it. He works like the audit isn't three streets away with a shredder.</p>
<<set $game_state.current_canvas = "hub_calloway_fileroom">>
<<set $game_state.current_node = "hub_calloway_fileroom.base">>
<<script>>setup.markCanvasTriggered("hub_calloway_fileroom");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_calloway_fileroom.base") === -1) { vn.push("hub_calloway_fileroom.base"); }<</script>>
<<nobr>>
<<link "Talk to him." "Canvas_hub_calloway_fileroom_Node_talk">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "calloway_believes", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "gte", "value": 0}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('hub_calloway_fileroom:cc0') ? '' : 'unlocked-choice'">
<<link "Get close to him." "Canvas_rung_calloway_contact_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_calloway", "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_calloway", "arousal", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_calloway_fileroom:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Get close to him.">Get close to him. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "calloway_believes", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "gte", "value": 6}, {"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('hub_calloway_fileroom:cc1') ? '' : 'unlocked-choice'">
<<link "Take him in your mouth." "Canvas_rung_calloway_oral_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_calloway", "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_calloway", "arousal", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "calloway_oral_once", "set");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_calloway_fileroom:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Take him in your mouth.">Take him in your mouth. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "calloway_believes", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "calloway_flinch_resolved", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_calloway", "trait_key": "corruption", "operator": "gte", "value": 18}]})>>
<span @class="setup.isChoiceVisited('hub_calloway_fileroom:cc2') ? '' : 'unlocked-choice'">
<<link "Take him — all the way." "Canvas_loop_calloway_sex_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "calloway_fucked_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_calloway_fileroom:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Not yet — he has to trust you all the way down first.">Not yet — he has to trust you all the way down first.</span><br>
<</if>>
<<link "Leave him to the paper." "Location_vance_securities">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "lt", "value": 1}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Walk me through the ghost. From the start. The parts nobody let you finish.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> ...Fine. You keep up, and you keep it in this room. I've had enough people carry half of it out and call me paranoid.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "calloway_drains_done", "operator": "gte", "value": 1}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Anything new on the ghost?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> For you? Everything I've got. Don't know what I ran this on before you walked in.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He hands it over before she's done asking. He'll never know the file room's been hers since the night his own current gave up where the vault is.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_calloway_fileroom">>
<<set $game_state.current_node = "hub_calloway_fileroom.talk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_calloway_fileroom.talk") === -1) { vn.push("hub_calloway_fileroom.talk"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_calloway", "relation", "add", 2.0, false, null);setup.showEffectNotification();<</script>>
[[Keep at it.->Location_vance_securities]]<img src="./videos/scenes/calloway_meet.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He's at the file wall when she comes in, and he doesn't turn. Just clocks the badge in the dark glass and files her under the same heading as everyone else Mercer's sent down here.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> Nobody reads the file. They read the summary, sign the close order, and go to lunch. That what you're here to do — sign it?</div></div><p>He says it the way he's said it a hundred times, to a hundred minders.</p><span id="cascade-b2-beat-1"><<linkreplace "Take the hunt seriously.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The rogue's real. You're the only one still looking. That's the file I'd want to read.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/calloway.jpg" alt="Calloway" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Calloway</strong> ...Huh. They usually don't bother learning the words. Sit down. Don't touch anything.</div></div>[[Get to work.->Location_vance_securities]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_calloway_meet">>
<<set $game_state.current_node = "cap_calloway_meet.base">>
<<script>>setup.markCanvasTriggered("cap_calloway_meet");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_calloway_meet.base") === -1) { vn.push("cap_calloway_meet.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "calloway_met", "set");<</script>><img src="./videos/scenes/archive_placement.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The badge desk scans her lanyard without looking up and waves her at an empty chair. One of a dozen, most already boxed. She's on Calloway's division now, or what the audit's left of it.</p><p>The woman at the next desk clocks the new badge and doesn't bother pretending she's working.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/reyes.jpg" alt="Reyes" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Reyes</strong> Nobody told you what you walked into. Fine — since I'm the only one who's going to.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/reyes.jpg" alt="Reyes" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Reyes</strong> Voss over there's done thirty years and still thinks Calloway hung the moon. Marr does the crossword. That's the whole job now. Vane you'll barely notice, keeps his head down, does it clean. And me, I'm gone the second something better calls back.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/reyes.jpg" alt="Reyes" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Reyes</strong> Advice? Answer the auditors, not him. Calloway's chasing a ghost, and half of us think the ghost is just him coming apart. Don't catch it.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Four people running out the clock on a dead floor. To them she's one more temp badge, gone before the boxes are. Exactly what the cover needs. No one worth remembering.</div></div>
<<set $game_state.current_canvas = "cap_archive_placement">>
<<set $game_state.current_node = "cap_archive_placement.base">>
<<script>>setup.markCanvasTriggered("cap_archive_placement");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_archive_placement.base") === -1) { vn.push("cap_archive_placement.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "floor_placed", "set");<</script>>
[[Find the file room.->Location_vance_securities]]<img src="./videos/scenes/archive_cover.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The plain kit holds all the way up. The junior-analyst badge Mercer bought clean, the grays that make her no one worth a second look, a desk in a division being quietly shut down. The lift opens on Vance Securities: half the lights off, half the desks empty, the audit already eating it from inside.</p><p>The file room is Calloway's. He runs the company's hunt for the rogue out of it, and the floor treats him like a crank chasing a ghost. The paper he keeps has no index. The only map of it lives in his head.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A plain company errand, the way Mercer put it. Get in, take the room, bring it back. She doesn't turn over what might sit under a job this simple. First she needs the man who keeps it.</div></div>
<<set $game_state.current_canvas = "cap_archive_cover">>
<<set $game_state.current_node = "cap_archive_cover.base">>
<<script>>setup.markCanvasTriggered("cap_archive_cover");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_archive_cover.base") === -1) { vn.push("cap_archive_cover.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "archive_started", "set");<</script>>
[[Get to work.->Location_vance_securities]]<img src="./videos/scenes/salvage_relaunch.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She comes up the ramp into the grey morning, and the comm in her jaw clicks live before she's ten steps clear. Mercer, who always knows the minute she's operational again.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You went dark. Days. I don't like dark, and I like even less what walks back out of it. Who put hands on you.</div></div><span id="cascade-b3-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> A mechanic. Off the books. I'm operational.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> A mechanic. You let some dockside butcher open you up and go rooting around in company property. You have any idea what you're worth. What's in you.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> More than you'll ever say out loud. I've met the part you keep the key to.</div></div><span id="cascade-b3-beat-1"><<linkreplace "Take the order.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> New target. Calloway — Vance Securities, internal division. He runs the hunt for the rogue from the inside, and he keeps a file room nobody audits. Get in. Bring me what's in it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There's a junior-analyst kit in your quarters. Wear it onto that floor — badge, plain grays, the whole nothing look. Not your own face. A division under audit remembers anyone who looks worth remembering.</div></div><span id="cascade-b3-beat-2"><<linkreplace "Say yes.">><p>She says yes the way she says yes to everything. But it sits on a new floor now. Every order he gives her, he gives holding the one key that can cut the thing at the root of her. He's never once had to say so, because until three days ago she didn't know it was there. Now she does. It doesn't change the yes. It changes what she's saying yes for.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You still in one piece?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Operational.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Then move. And Wren — next time you break, you break to me. Not to some yard rat. What's mine gets fixed by mine. Understand.</div></div>[[Go to work.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "salvage_relaunch">>
<<set $game_state.current_node = "salvage_relaunch.base">>
<<script>>setup.markCanvasTriggered("salvage_relaunch");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_relaunch.base") === -1) { vn.push("salvage_relaunch.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "salvage_relaunched", "set");<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("cover_analyst");setup.showEffectNotification();<</script>><p>The lift opens on the penthouse and Mercer looks up from the glass wall and stops. Whatever he keeps her for goes out of his face and something colder comes in. He crosses the floor and takes her jaw in one hand, turning her face to the light like a man checking a coin for a file-mark.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> What did they do to you.</div></div><span id="cascade-b2-beat-0"><p>She doesn't answer. There isn't an answer that helps her. He turns her head the other way, reading the wrongness off her the way she reads it off a man. Except he had the building of her, and he knows the manual.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You go dark for days, you come back moving like that, the core reading wrong through your skin. No. An asset that limps is a liability, and I don't hand the Chairman a liability.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Hear the refusal.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You get nothing from me like this. No target, no work, nothing. I'm not spending you broken. Go get yourself right, then come back and work. Not before.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Now get out of my sight.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Go.">><p>The lift takes her back down. She has her answer, and it's the one the dock already gave her: there's no working her way back in until she can fire. Which means the berth. Which means coin. Which means down the gate, where coin gets made.</p>[[Back down.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "salvage_mercer_shocked">>
<<set $game_state.current_node = "salvage_mercer_shocked.base">>
<<script>>setup.markCanvasTriggered("salvage_mercer_shocked");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_mercer_shocked.base") === -1) { vn.push("salvage_mercer_shocked.base"); }<</script>>
<<script>>advanceTime(3);<</script>><img src="./videos/scenes/kess_extraction.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The lamp is up, not down. He wants to see.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Sit. No — lie down. I've had the tools out since you told me it fired.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I can take it now. Couldn't before, and I want you to know the difference before I open you.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Ask the difference.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What changed.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Your build's been talking to it. While that thing's answering in his voice the guard's asleep, and a sleeping guard I can cut around.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Blind, it takes you with it. I said that and I meant it.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Get on the bench.">><p>She lies face-down on the steel, bare from the hip. The fourth part is still in her and the key is still beside it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Arms flat. Last time you're on this bench for this, and I'd rather it was quick than pretty.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Hold still.">><p>It takes longer than the parts did. He works under the core rather than in it, and twice he stops and does nothing at all for a while.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Don't talk. If it wakes I want to hear it before you feel it.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Wait.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Two years that's been sat in you, and it's not coming out because I asked it nicely. Talk to me about something else.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Like what.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Anything. People bleed less when they're annoyed.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Wait it out.">><p>Then a change in the pressure. Something coming free that was never meant to come free. The quality of the room changes with it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. That's out.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Don't look at me like that. It came out clean, and that's the last surprise you get tonight.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Sit up.">><p>He puts it on the steel in front of her. It is smaller than a coin and it does not look like anything.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Eleven years of somebody's paperwork, and that's the whole of what they put in you to make it stick.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Look at it.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It's small.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> They always are. The expensive part isn't the thing, it's the years of arguing about what it ought to do.</div></div><p>She does not touch it. Two years of her life is on the bench and it is a grey speck.</p><span id="cascade-b2-beat-8"><<linkreplace "The file.">><p>He wipes his hands, pulls the file over, and sets the chip down on the sealed page. A man matching a key to a lock, because that is what he is doing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Hardware's honest. Whoever built one built the other.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Same hand. I told you. Watch.</div></div><span id="cascade-b2-beat-9"><<linkreplace "Watch.">><p>The seal on the page reads the thing that came out of her, decides it is allowed, and lets go.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There's your page. I've not looked. I'll be over there.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And don't thank me for it. You paid for every hour.</div></div><p>He goes over there.</p><span id="cascade-b2-beat-10"><<linkreplace "Read it.">><p>Her line is on the index where it has always been, and the designation on it is older than she is by four years.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> They wrote me down four years before there was anything to write down.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Keep reading.">><p>Under it, the word she got three pages into a file in this room and could not read past: BUILD.</p><p>Above her line and below it, the others. The index does not start at one.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> There's an office in this. People. Eleven years of somebody coming to work.</div></div><span id="cascade-b2-beat-12"><<linkreplace "The columns.">><p>Two date columns, the way Kess read them off it. The first is filled all the way down. The second is filled most of the way down.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The second one's when they stopped.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Aye.</div></div><span id="cascade-b2-beat-13"><<linkreplace "Find your own.">><p>Hers is blank. She goes up the column and back down it, counting the ones that aren't, and stops counting.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Most of them are dead.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Most of them are stopped. That's the word they used and I'd not go past it.</div></div><span id="cascade-b2-beat-14"><<linkreplace "The last line.">><p>The programme closes on the page before hers. Sign-offs, a date, an office winding up work it had finished.</p><p>Her page was sealed eight months after that, by a hand on none of the sign-offs. Somebody outside came back to a closed thing and shut one page.</p><span id="cascade-b2-beat-15"><<linkreplace "Put it down.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Mercer sent her up to a file room to steal a company's paperwork and never once looked at what he was sending. He put her on it himself. Two years of errands, and the last one was to go and fetch herself.</div></div><span id="cascade-b2-beat-16"><<linkreplace "Say something to him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Kess.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I'd rather not know. You'll tell me if you need a thing built and I'll price it, and the rest of it's yours.</div></div><p>That is as close to kindness as the Reach comes, and she takes it as such.</p><p>She puts the file under her arm and stands up off the bench with nothing in her that answers to anybody.</p><p>Somewhere out there is a man who came through a door for her and would not say why he cared. He does not have a name yet.</p>[[Take it and go.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_extraction">>
<<set $game_state.current_node = "cap_extraction.base">>
<<script>>setup.markCanvasTriggered("cap_extraction");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_extraction.base") === -1) { vn.push("cap_extraction.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "leash_cut", "set");setup.applyAndNotifyFlag("player", null, "file_read", "set");<</script>><p>He is still in her ass and still down on her back, spent and heavy and going nowhere. She reaches down inside for the old pull, the thing that opens a man at the base of the spine, and on him there is nothing to catch on.</p><span id="cascade-b1-beat-0"><p>Cold socket, dead as before. The same nothing as every time he has finished in her, and the exact shape of the last two years.</p><p>She stays the twenty minutes he wants, because leaving early would be a change in her, and there is nothing in this room she can afford to change.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Come whenever. You know where the door is.</div></div></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.cold">>
<<script>>setup.markCanvasTriggered("mercer_drain_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.cold") === -1) { vn.push("mercer_drain_canvas.cold"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Get your coat.->Location_mercer_room]]<p>His cock is still in her ass, softening, his weight settled forward on her back. She reaches for it at the finish, the same reach she made on Kess's cradle.</p><span id="cascade-b1-beat-0"><p>Something small at the base of her spine says its piece into an empty room. Nothing hears it. Nothing pushes back.</p><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><p>She waits, because waiting is the only part of this she was ever given to do. Ten seconds. Twenty.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You've gone quiet on me. You always did go quiet at the end.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Nothing.">><p>It is the same nothing as every time he has finished in her. No give. No opening. The exact shape of the last two years.</p><span id="cascade-b1-beat-3"><<linkreplace "Let him have his hour.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> That's better. That is genuinely better. You want a drink? No. No, of course. I'll have yours.</div></div><p>He does up his belt and pours, and he is happier than she has seen him since the floor.</p><span id="cascade-b1-beat-4"><<linkreplace "Hold still.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She had not expected anything and she is disappointed anyway. That is new. The part is dead in her, cooked the way he said it would cook. Somebody paid twenty-five coin for that.</div></div><p>She stays the twenty minutes he wants, because leaving early would be a change in her, and there is nothing in this room she can afford to change.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Come whenever. You know where the door is.</div></div>[[Get your coat.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.try1">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.try1") === -1) { vn.push("mercer_drain_canvas.try1"); }<</script>>
<<script>>advanceTime(30);<</script>><p>He is still buried in her ass, his belly warm against her back, his cum in her. She reaches for it at the finish. This time something reaches back.</p><span id="cascade-b1-beat-0"><p>Not the part. The other thing, the older one, the one Kess found under her core and did not like.</p><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><p>It closes on her the way a hand closes. Everything below the hips goes rigid and stays rigid, and none of it is hers.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Christ. There. There — hold that, don't you dare move.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Don't make a sound.">><p>What is trying to get out of her is not a sound he has ever heard her make, and she holds it behind her teeth.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Two years and you've never once done that. I'd have said you couldn't. I'd have been wrong.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Let him take it for what he wants.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> The floor. The glass. The woman with the plants. I'd give the lot of it back for a Thursday that went like this one is going.</div></div><p>He settles in behind her, pleased, in no rush to be anywhere at all.</p><span id="cascade-b1-beat-4"><<linkreplace "Count.">><p>She counts. At eleven her hand has closed on the bed frame hard enough to shake it, and she opens it finger by finger.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You're shaking. That's new as well. Everything about tonight is new and I've decided not to ask why. Are you cold?</div></div><span id="cascade-b1-beat-5"><<linkreplace "Give him something.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It's cold in here.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> It is. I keep meaning to do something about that and I never do. There's a stove two rows over I could have for nothing.</div></div><p>He does not look at her face. He has not looked at her face in two years.</p><span id="cascade-b1-beat-6"><<linkreplace "Wait it out.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> It did nothing at all last time. Tonight it did something, and what it did was hold her down. She cannot tell whether that counts as progress.</div></div><p>It lets go all at once, the way a cramp lets go, and leaves her legs useless for a minute. She waits until they work.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Thursday, then. I've started liking having a Thursday. Don't tell anyone.</div></div>[[Get your coat.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.try2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.try2") === -1) { vn.push("mercer_drain_canvas.try2"); }<</script>>
<<script>>advanceTime(30);<</script>><p>His cock is still in her ass, heavy, his breath going out slow against her shoulder. She reaches for it at the finish. This time nothing stops her.</p><span id="cascade-b1-beat-0"><p>Something that has been shut since before she can remember is not shut. No warning. It is simply not there.</p><span id="cascade-b1-beat-1"><<linkreplace "Reach.">><p>She reaches down inside for the old pull, the thing that opens a man at the base of the spine, and on him it catches.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Stay there a minute. I've got nowhere to be and you've got nowhere better, and I've decided that's what a Thursday is.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Hold it.">><p>Not secrets. The beginning of one. A man belonging to her, the width of a hair, and hers.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There's a stove going two rows over for nothing. I keep not buying it. I'd rather have the coin in a bottle and the cold to complain about.</div></div><span id="cascade-b1-beat-3"><<linkreplace "Then it counts.">><p>Then something goes down a list. An item. An item. A gap. On the gap it comes back and shuts the door.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Nine years I had a man to do that sort of thing. Never learned his name either. You'd think I'd have learned one of them.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Check it.">><p>She reaches again while he is still inside her. Nothing catches. Cold socket, dead as before.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Don't move yet. That's the whole of what I've got left, that bit, and I'd like it to run long.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Wait it out.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Two years of nothing was survivable while it was a wall. It is a door. It opened, and something on the other side counted her and shut it.</div></div><p>He does up his belt one-handed and goes for the glass, pleased in the ordinary way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Best part of it now is nobody signed for it. You come because you come, and that's worth more than the floor was.</div></div><p>He has no idea he has said anything.</p>[[Get your coat.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.try3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.try3") === -1) { vn.push("mercer_drain_canvas.try3"); }<</script>>
<<script>>advanceTime(30);<</script>><p>His cock is still in her ass and his whole weight is on her back, and he has not moved since he came. She reaches down inside for the old pull, the thing that used to open a man at the base of the spine.</p><span id="cascade-b1-beat-0"><p>It catches. She waits for the list. For the item, and the item, and the gap where she is that always closes. Nothing comes down. Nothing comes at all.</p><p>The room stays exactly as quiet as a room.</p><span id="cascade-b1-beat-1"><<linkreplace "Take it.">><video src="./videos/sex/mercer_lockup_anal_drain_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Then the whole of him comes loose. Not a skim, the live current of him going soft and honest through her while he lies on her back with his cock still in her and lets it happen.</p><span id="cascade-b1-beat-2"><<linkreplace "Ask him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Who signed for me.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Halloran. Asset Services, fourth floor. Never met the man. A signature on a transfer and a number I never called.</div></div><p>His voice comes out even. He answers the way a man answers in his sleep.</p><span id="cascade-b1-beat-3"><<linkreplace "And what was he told.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What was Halloran told I was.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Sensitive recovery. One of theirs, on loan, keep her off the manifests. That's the whole of it. Four lines and a signature.</div></div><span id="cascade-b1-beat-4"><<linkreplace "And you.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And what were you told.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Less. She's yours, she does what you say, don't break her, don't ask. I didn't ask. It never once occurred to me to ask.</div></div><p>There is no shame in it. There is nothing in it at all.</p><span id="cascade-b1-beat-5"><<linkreplace "The key.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The key in your coat. What is it for.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Christ knows. They handed it over with you. Said if she stops working, this is who you call. So I took it for the off-switch.</div></div><span id="cascade-b1-beat-6"><<linkreplace "Two years.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Two years in a coat pocket. I thought it was there so you couldn't turn on me. A perk, not a job. I never once asked what it did.</div></div><p>He carried the thing that owns her as a courtesy, and never had the faintest idea what it was for.</p><span id="cascade-b1-beat-7"><<linkreplace "Then say the rest.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then how does it know you.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> It doesn't know me. Mine only speaks for me. I remember, because it annoyed me. Mine. Like there were others out there with one.</div></div><span id="cascade-b1-beat-8"><<linkreplace "Ask for the rest of them.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Who else.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> How would I know. I got a key and a girl and a floor to lose. I wasn't senior. I was the one who signed.</div></div><p>Nothing in him goes any further. He is the bottom of it and he was never anything else.</p><span id="cascade-b1-beat-9"><<linkreplace "Let go.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Two years owned by a man who was handed her with four lines and a signature. The leash is off for him and on for everyone else on that list, and she has no idea how long the list is.</div></div><span id="cascade-b1-beat-10"><<linkreplace "Let him come back.">><p>He surfaces ten minutes later on his own bed, out of her at last, blinking, the good mood of a man who has had a nice evening still on him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Where'd you go. Sit down and have one. There's a whole bottle of it and it came in a box.</div></div><p>She goes out past the shuttered stall and up into the market carrying, for the first time since the floor, something that is not on loan.</p><p>Behind her he is pouring, and none the wiser, and pleased.</p>[[Get your coat.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.d0">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.d0") === -1) { vn.push("mercer_drain_canvas.d0"); }<</script>>
<<script>>advanceTime(3);<</script>><p>He is still in her ass with his weight down on her, exactly where he has been for three of these. She reaches down inside for the old pull, the way she has three times now.</p><span id="cascade-b1-beat-0"><p>It catches. She holds still and waits to be shut, and the list comes down the way it has always come down. An item. An item. And then the gap where she is, and the thing that lives in that gap turning over to look at her.</p><span id="cascade-b1-beat-1"><<linkreplace "Hold it.">><p>Something at the base of her spine answers it in his voice. Two words, maybe three. She never hears them.</p><p>The list moves on past her and the door stays open.</p><span id="cascade-b1-beat-2"><<linkreplace "Take it.">><video src="./videos/sex/mercer_lockup_anal_answered_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Then the whole of him comes loose, the same as the first time, the live current of him going soft and honest through her while he lies on her back with his cock still in her ass.</p><span id="cascade-b1-beat-3"><<linkreplace "Hold it open.">><p>She holds it open longer than she needs to, the way you press a bruise to check. Nothing comes back for it. The key is awake on Kess's bench and it has nothing left to say about her.</p><span id="cascade-b1-beat-4"><<linkreplace "Ask him something.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Do you feel different.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Different. No. Should I? I feel like a man who's had a nice evening. That is more than I've had in a month.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Let go.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Every door that has opened for her down here was somebody else's. His bench, that hand, a key on a cloth. The thing that spoke for her just now is in her, and nobody gave it to her.</div></div><span id="cascade-b1-beat-6"><<linkreplace "Let him come back.">><p>He surfaces ten minutes later on his own bed, out of her at last, blinking, the good mood of a man who has had a nice evening still on him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Where'd you go. Sit down and have one. That chair's oak. I keep telling you and you keep not sitting in it.</div></div><p>She goes out past the shuttered stall and up into the market carrying, for the first time since the floor, something that is not on loan.</p><p>Behind her he is pouring, and none the wiser, and pleased.</p>[[Out through the stall.->Location_underworld_market]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.d1">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.d1") === -1) { vn.push("mercer_drain_canvas.d1"); }<</script>>
<<script>>advanceTime(3);<</script>><p>Same room, same bottle, his cum still in her ass and his hand still flat on her back.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Thursday. I've stopped pretending I don't count them. A man my age gets one thing to look forward to and stops being clever about it.</div></div><p>He gets what he always got.</p><span id="cascade-b1-beat-1"><<linkreplace "Take it.">><p>The drain fires the way it fires now. No discovery in it, just her owner coming loose into her and the minutes going with him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Don't rush off. That's the whole of what I've got left, that bit, and I'd like it to run long.</div></div><span id="cascade-b1-beat-2"><<linkreplace "Wait it out.">><p>He says it every time, and every time he has just said it for the first time. There is nothing left in him she needs.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You'll come round again. You always do. I'd not have bet on that a year ago and I'd have been wrong.</div></div><p>He surfaces grateful, pours himself one, and asks if she's stopping. She is not. She never is.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Thursday, then. I'll get a second glass in. A man ought to have two glasses.</div></div>[[Get your coat.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "mercer_drain_canvas">>
<<set $game_state.current_node = "mercer_drain_canvas.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_drain_canvas.done") === -1) { vn.push("mercer_drain_canvas.done"); }<</script>>
<<script>>advanceTime(30);<</script>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_finish_facial_t5"] to ($game_state.media_cycle["sex_mercer_lockup_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_finish_facial_t5/c47fe8c4b56.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_finish_facial_t5/c07381d25dc.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_finish_facial_t5/c34492a437d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_finish_facial_t5/c948373234d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes on her face, one hand on himself and one in her hair, and looks down at what he has put there with plain satisfaction. Nothing comes loose but him. The drain stays shut. It only opens the one way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There. Don't take it on the sleeve, there's a cloth on the crate. I'm not an animal about it and I never was.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_finish_inside_t5"] to ($game_state.media_cycle["sex_mercer_lockup_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_finish_inside_t5/c0e36cfc5c3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_finish_inside_t5/c4d4df0b08a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_finish_inside_t5/c2441a33809.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_finish_inside_t5/cf13f8c9ffd.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes in her cunt at the same unhurried pace, holds there a moment, and does up his belt one-handed. His cum runs on the inside of her thigh and she leaves it. She has taken nothing. Not this way.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Come Thursday. Or don't. You know where the door is.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_anal_finish_t5"] to ($game_state.media_cycle["sex_mercer_lockup_anal_finish_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_anal_finish_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_anal_finish_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_anal_finish_t5/cb9b8d08334.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_anal_finish_t5/cbc9427b847.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_anal_finish_t5/cc63b029e44.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_anal_finish_t5/cd7f779eaf8.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes in her ass at the same pace and holds there, one hand still flat on her back, breathing out like a man sitting down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Ah. Stay there a moment. Don't go anywhere yet.</div></div>
<</if>>
<<set $game_state.current_canvas = "loop_mercer_finisher">>
<<set $game_state.current_node = "loop_mercer_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_mercer_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_mercer_finisher.climax") === -1) { vn.push("loop_mercer_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Get your coat." "Location_mercer_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc0");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Let it go — wrong gear." "Location_mercer_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc1");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Let it go — the drain's empty. Take a night on the feed line at the berth and it reloads." "Location_mercer_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc2");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc3') ? '' : 'unlocked-choice'">
<<link "Reach for it." "Canvas_mercer_drain_canvas_Node_cold">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc3");<</script>><<script>>advanceTime(30);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc4') ? '' : 'unlocked-choice'">
<<link "Reach for it at the finish." "Canvas_mercer_drain_canvas_Node_d0">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_drains_done", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_leash_state", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "owner_drained", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc4");<</script>><<script>>advanceTime(90);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc5') ? '' : 'unlocked-choice'">
<<link "Reach for it." "Canvas_mercer_drain_canvas_Node_cold">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc5");<</script>><<script>>advanceTime(30);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc6') ? '' : 'unlocked-choice'">
<<link "Reach for it." "Canvas_mercer_drain_canvas_Node_cold">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc6");<</script>><<script>>advanceTime(30);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc7') ? '' : 'unlocked-choice'">
<<link "Reach for it." "Canvas_mercer_drain_canvas_Node_try1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_installed", "set", 0.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_attempts", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc7");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc8') ? '' : 'unlocked-choice'">
<<link "Reach for it." "Canvas_mercer_drain_canvas_Node_try2">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_installed", "set", 0.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_attempts", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc8");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 3}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc9') ? '' : 'unlocked-choice'">
<<link "Reach for it." "Canvas_mercer_drain_canvas_Node_try3">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_installed", "set", 0.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_attempts", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc9");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 3}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc10') ? '' : 'unlocked-choice'">
<<link "Reach for it at the finish." "Canvas_mercer_drain_canvas_Node_d1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_drains_done", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_leash_state", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "leash_answered", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc10");<</script>><<script>>advanceTime(90);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "gte", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_finisher:cc11') ? '' : 'unlocked-choice'">
<<link "Take it." "Canvas_mercer_drain_canvas_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "mercer_drains_done", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_finisher:cc11");<</script>><<script>>advanceTime(60);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_false"}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_false"}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 3}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 3}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "gte", "value": 2}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_mercer_finisher = [{"text": "Get your coat.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Let it go \u2014 wrong gear.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]}}, {"text": "Let it go \u2014 the drain's empty. Take a night on the feed line at the berth and it reloads.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]}}, {"text": "Reach for it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_false"}]}}, {"text": "Reach for it at the finish.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 1}]}}, {"text": "Reach for it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_false"}]}}, {"text": "Reach for it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "lt", "value": 1}]}}, {"text": "Reach for it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 1}]}}, {"text": "Reach for it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 2}]}}, {"text": "Reach for it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 3}]}}, {"text": "Reach for it at the finish.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "lt", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 3}]}}, {"text": "Take it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_leash_state", "operator": "gte", "value": 2}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_mercer_finisher",
choices: window._engineNoExitsDiag_loop_mercer_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_mercer_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_mercer_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "controller_off", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "owner_drained", "operator": "is_false"}]})>>
<p>He has the bottle out of the case already and a second glass on the crate that nobody is going to drink from.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Thursday. Look at that. I said Thursday and here's Thursday. That box has been the best week I've had in a year.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 3}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "leash_answered", "operator": "is_false"}]})>>
<p>The fourth part has been in her three days and she has stopped thinking about it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There she is. I bought a chair. Two rows over, a man selling chairs to people with no floor to put them on, and I thought — why not.</div></div><p>She doesn't sit in it. He is pleased she came anyway.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "mercer_found", "operator": "is_true"}]})>>
<p>The bulb is on and the bottle is already down off the crate. He has his shoes off, which down here passes for being at home.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There she is. Shut that behind you. The market has ears, and half of them are mine. That is the worse half.</div></div>
<</if>><span id="cascade-b3-beat-0"><<set _bp to random(0, 3)>>
<<if _bp is 0>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> A man came in today wanting a ticket dated back four years. I did it in an hour.</div></div>
<<elseif _bp is 1>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Two stalls down there's a woman selling boots she hasn't got. I admire it. I couldn't do it.</div></div>
<<elseif _bp is 2>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> The bulb went twice last week. I keep spares now. I never once did that upstairs.</div></div>
<<else>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There's a lad two rows over undercutting me on manifests. He'll be gone by winter. They always are.</div></div>
<</if>><p>He sets the glass down and turns her by the shoulder, and the turning is the whole of the asking.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Go on, then. You know how I like it and I know you know, and that is the restful part of it.</div></div></span>
<<set $game_state.current_canvas = "loop_mercer_lockup">>
<<set $game_state.current_node = "loop_mercer_lockup.intro">>
<<script>>setup.markCanvasTriggered("loop_mercer_lockup");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_mercer_lockup.intro") === -1) { vn.push("loop_mercer_lockup.intro"); }<</script>>
<<nobr>>
<<link "Get on your knees." "Canvas_loop_mercer_lockup_Node_base_oral_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Bend over the end of the bed." "Canvas_loop_mercer_lockup_Node_base_vaginal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Give him your ass." "Canvas_loop_mercer_lockup_Node_base_anal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_oral_t5"] to ($game_state.media_cycle["sex_mercer_lockup_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_oral_t5/c021d071d3f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_oral_t5/c271aa0ba1d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_oral_t5/c415c74dd30.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_oral_t5/ce3a7ecf883.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees on the concrete, his cock further back in her mouth than she has room for. He holds her down on it a second at a time, unhurried, until her nose is at his balls. She sucks him through it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Every time you come now. Two years of never, and now every time.</div></div>
<<set $game_state.current_canvas = "loop_mercer_lockup">>
<<set $game_state.current_node = "loop_mercer_lockup.base_oral_mercer">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_mercer_lockup.base_oral_mercer") === -1) { vn.push("loop_mercer_lockup.base_oral_mercer"); }<</script>>
<<nobr>>
<<link "Keep him in your mouth." "Canvas_loop_mercer_lockup_Node_base_oral_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Get up and bend over the end." "Canvas_loop_mercer_lockup_Node_base_vaginal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_lockup:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_mercer_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_lockup:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_routine_t5"] to ($game_state.media_cycle["sex_mercer_lockup_routine_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_routine_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_routine_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_routine_t5/c8bc5179335.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_routine_t5/c8fad95b0cf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_routine_t5/c63f9b3485d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_routine_t5/ca7213f0fbd.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He gets his cock into her cunt and settles into it, unhurried, one hand flat between her shoulder blades and the other still holding the glass. Her cunt is wet and takes the whole length of him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Same as ever. I like that there's a same-as-ever left. Not one thing about this has changed.</div></div>
<<set $game_state.current_canvas = "loop_mercer_lockup">>
<<set $game_state.current_node = "loop_mercer_lockup.base_vaginal_mercer">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_mercer_lockup.base_vaginal_mercer") === -1) { vn.push("loop_mercer_lockup.base_vaginal_mercer"); }<</script>>
<<nobr>>
<<link "Let him have it." "Canvas_loop_mercer_lockup_Node_base_vaginal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_loop_mercer_lockup_Node_base_oral_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Let him take your ass instead." "Canvas_loop_mercer_lockup_Node_base_anal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_lockup:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_mercer_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_lockup:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_anal_t5"] to ($game_state.media_cycle["sex_mercer_lockup_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_anal_t5/c1bd0bd2bb0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_anal_t5/c4cf27c1489.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_anal_t5/c534167cfb9.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_anal_t5/cce4ff8e7cd.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He puts his cock in her ass the way he always got round to it, and she opens for him out of two years of practice. He is thick and does not rush it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> That's the one. That was always the one. You never made a fuss about this.</div></div><p>She gets a hand back around his wrist, skin on skin, and holds it there while he fucks her ass. That is the seat. The drain sits in the contact and waits for the finish.</p>
<<set $game_state.current_canvas = "loop_mercer_lockup">>
<<set $game_state.current_node = "loop_mercer_lockup.base_anal_mercer">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_mercer_lockup.base_anal_mercer") === -1) { vn.push("loop_mercer_lockup.base_anal_mercer"); }<</script>>
<<nobr>>
<<link "Take it in the ass." "Canvas_loop_mercer_lockup_Node_base_anal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on him." "Canvas_loop_mercer_lockup_Node_base_vaginal_mercer">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_mercer_lockup:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — and reach for it." "Canvas_loop_mercer_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_mercer_lockup:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><video src="./videos/scenes/kess_install.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The bench is clear and the lamp is down low over it.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> First one. Everything I could read off that lock while it was open, cut down to sit where the drain sits.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 2}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Sweep head. Wider than the last one. I'll have to take more of the seam. Lie still and breathe.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 3}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Isolator. Heavy for its size, and it sits deeper. If it bites this time it bites this, not you.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 3}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Last one. Stacked. Three seatings in one seam. Hold still. After this you're free or I'm out of ideas.</div></div>
<</if>><span id="cascade-b6-beat-0"><p>He clears a space with his forearm and folds a coat at one end for her face.</p><span id="cascade-b6-beat-1"><<linkreplace "Get on the bench.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Down. Face in that, arms flat at your sides. I work quicker when I'm not asking.</div></div><p>She takes her trousers down and lies face-down on the steel, bare from the hip, because that is where the seam is.</p><span id="cascade-b6-beat-2"><<linkreplace "Hold still.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Colder than the cradle. I'd rather steel than a pad I can't wipe down.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Arms stay where they are. You move while I'm in the seam and I close it on my own thumb.</div></div><p>His hand finds the ridge straight to it.</p><span id="cascade-b6-beat-3"><<linkreplace "Let him open it.">><p>It gives the way it gave for Bastien's men. Patient, a quarter turn, then all at once.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There it is. Same as it was. Whoever built you liked a clean edge.</div></div><span id="cascade-b6-beat-4"><<linkreplace "Wait.">><p>The whole lower half of her goes to something that is not pain and is not pressure, and has no word, because she was never built to be given one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Breathe normal. You're holding it, and holding it tightens the seam on me.</div></div><span id="cascade-b6-beat-5"><<linkreplace "Breathe.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> This is the part where a person swears at me. You lie there like a bench vice.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Not a complaint. Makes it quick.</div></div><p>His hands go in past the second knuckle and stop being hands.</p><span id="cascade-b6-beat-6"><<linkreplace "Feel him working.">><p>Something is happening inside her housing at a depth nothing has ever reached from the outside, unhurried, and she can follow every inch of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Seating it now. It wants to sit where the drain sits. That is the reason this might work and the reason it might cook you.</div></div><span id="cascade-b6-beat-7"><<linkreplace "Stay still.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Bastien's men opened this to take something out, and they laughed while they did it. This one is putting something in and telling her to breathe. Her body cannot find the difference. Only the room can.</div></div><p>It seats with a small definite pressure, the way a bolt seats, and stays. He presses the ridge flat with his thumb twice and steps back to the lamp.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> That's in. It sits until it's used or it's cooked. Go and get it used.</div></div>[[Get dressed.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "kess_install_part">>
<<set $game_state.current_node = "kess_install_part.base">>
<<script>>setup.markCanvasTriggered("kess_install_part");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_install_part.base") === -1) { vn.push("kess_install_part.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "part_held", "set", 0.0, true, null);setup.applyAndNotifyTrait("player", null, "part_installed", "set", 1.0, true, null);setup.showEffectNotification();<</script>><p>The key is where he left it, on the cloth, dead. He has not put it away. He has been waiting to find out whether it mattered.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Well?</div></div><span id="cascade-b1-beat-1"><<linkreplace "Tell him it worked.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It caught. Nothing came to shut it.</div></div><p>He sits back off the bench for the first time she has ever seen and lets out a breath through his nose.</p><span id="cascade-b1-beat-2"><<linkreplace "Tell him the rest.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> He said his only ever spoke for him. Like there were others.</div></div><p>The breath goes back in. He looks at the dead thing on the cloth for a while.</p><span id="cascade-b1-beat-3"><<linkreplace "Let him get there.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Then I've killed a lock and you're still locked. That's not a small thing, but it's the wrong thing to have done well.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Make him say it plainly.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It was never the key. It's what's IN you. That answers to anything with the right voice, and I've got no idea how many of those are walking round this city.</div></div><span id="cascade-b1-beat-5"><<linkreplace "Ask what he wants.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> So what do you want.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I want it back on. A dead lock tells me nothing. I need it talking, with you underneath it, or I'm guessing at the thing in you for the rest of your life.</div></div><span id="cascade-b1-beat-6"><<linkreplace "Let it sit.">><p>He does not fill the gap. He has never once filled a gap for her, and she has come to read that as the closest he gets to respect.</p><span id="cascade-b1-beat-7"><<linkreplace "Say yes.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Turn it on.</div></div><p>He picks the key up and it wakes under his thumb, and the old weight comes back down over her the way a coat does, and she stands there and lets it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Right. Then it's a part a go, off the small stalls, and a bench. That is me, and I won't guess how many. Bring me a talkback.</div></div><p>He goes back under the lamp. She has bought herself a leash to stand in until he is done, and she chose it. That is new.</p>[[Leave him to it.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "kess_the_chip_not_the_key">>
<<set $game_state.current_node = "kess_the_chip_not_the_key.base">>
<<script>>setup.markCanvasTriggered("kess_the_chip_not_the_key");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_the_chip_not_the_key.base") === -1) { vn.push("kess_the_chip_not_the_key.base"); }<</script>>
<<script>>advanceTime(45);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "parts_loop_open", "set");<</script>><img src="./videos/locations/kess_berth.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He has not been to bed. She can tell by the bench, which has been tidied the way a man tidies when he is close to something.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's open.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Wait for the rest.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Your box kept his hand the way it's built to. I fed that to the lock and the lock took it. It has no way of telling a hand off a courier plate from a hand in the room.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Ask what that means.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> So it's off.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> This is off. That's all I'll say standing here. The key's stopped talking — what that does to the thing in you is a different sentence and I'm not saying it yet.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Make him say the rest.">><p>He turns the key over once, the way he turns anything he has finished with, and sets it down on the cloth.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It never had to be near you. Two years in a coat pocket and it worked on you across a city. Off carries the same distance.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Ask how she'd know.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then how do I know.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You go and reach for it on the man it never let you touch. It catches or it doesn't. There's no reading I can take off this bench that beats that one.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Wait for him to ask.">><p>He doesn't ask who the man is. He hasn't asked once, and she has stopped expecting him to start.</p><span id="cascade-b2-beat-6"><<linkreplace "Let it go.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Two years of a thing in her that answered to a man who never once asked what it was for, and it came off a courier box and a hand he gave away for nothing.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Go on, then. Come back and tell me which one of us was right.</div></div><p>He goes back under the lamp. That is the whole of the goodbye down here, and she has stopped minding it.</p>[[Go and find out.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "kess_print_read">>
<<set $game_state.current_node = "kess_print_read.base">>
<<script>>setup.markCanvasTriggered("kess_print_read");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_print_read.base") === -1) { vn.push("kess_print_read.base"); }<</script>>
<<script>>advanceTime(45);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "controller_off", "set");<</script>><img src="./videos/scenes/mercer_print.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He is pouring before the door is properly shut.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Take that off. It's warm in here — warmer than out there, anyway. That is the one thing this room does better than the last one.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Take the coat off.">><p>She hangs it over the crate. The bottle goes down onto the floor to make room, and he watches her do it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Nine years I had somebody take a coat off me at a door. Now I hang my own on a nail. You don't miss it until it's gone.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Wait for him to come over.">><p>He doesn't come over. He pours the second one he has no intention of drinking and looks at her from the crate, taking his time, the way a man looks at something he already owns.</p><span id="cascade-b2-beat-3"><<linkreplace "Go to him.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Come here.</div></div><p>He gets a hand into her hair without hurry, the way a man takes hold of a thing he has owned a long time.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Two years and I never once had to raise my voice at you. People don't understand what that is worth.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Let him kiss you.">><p>He kisses her, and it is the first time anyone has in two years. He does it the way he does everything, unhurried and without asking, his fist still closed in her hair.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> I never did that enough. I thought about it often and I never did it.</div></div><span id="cascade-b2-beat-5"><<linkreplace "Let him take his time.">><p>He works her out of the rest of it one piece at a time, both hands, no impatience anywhere in him. He sets each thing on the crate instead of dropping it. Nobody has undressed her slowly in two years.</p><span id="cascade-b2-beat-6"><<linkreplace "Let him have your tits.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_print_tits_t5"] to ($game_state.media_cycle["sex_mercer_print_tits_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_print_tits_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_print_tits_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_print_tits_t5/c19a60d3b93.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_print_tits_t5/ca45c6c5abb.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_print_tits_t5/cada734d54d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_print_tits_t5/cb2ad6314a6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She stands naked on the concrete and lets him. He gets a hand on her tits, weighing one and then the other, working a nipple with his thumb, and never looks down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Two years and I never had an evening with nowhere to be at eight.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Let him turn you round.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_print_ass_t5"] to ($game_state.media_cycle["sex_mercer_print_ass_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_print_ass_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_print_ass_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_print_ass_t5/c9b9c58197d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_print_ass_t5/c084c5cdb6b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_print_ass_t5/ce78552a97d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_print_ass_t5/cf3adfb7dc6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He turns her round by the hip and gets both hands on her ass, weighing it the way he weighed her tits, squeezing hard enough to leave marks and letting go, unhurried.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You always did have the best ass in that building. I signed for that too.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Go down on him.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_print_knees_t5"] to ($game_state.media_cycle["sex_mercer_print_knees_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_print_knees_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_print_knees_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_print_knees_t5/c6df7a06f02.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_print_knees_t5/c7a743c8f23.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_print_knees_t5/c61c2696ccc.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_print_knees_t5/c6564bf8a0e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He puts a hand on her shoulder and presses her down onto the concrete. His cock is out before she settles. She sucks it. He fucks her mouth slowly and keeps talking.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> That's a new one. Two years and you never once. I'd have thought about it and not asked.</div></div><span id="cascade-b2-beat-9"><<linkreplace "Let him hold you there.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_print_throat_t5"] to ($game_state.media_cycle["sex_mercer_print_throat_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_print_throat_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_print_throat_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_print_throat_t5/c8c8262b84e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_print_throat_t5/c595cc07ad4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_print_throat_t5/ca40ac90429.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_print_throat_t5/cc4a48fb077.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He gathers her hair in his fist and holds her down on his cock until her nose is against his balls, and keeps her there through a whole sentence. Her eyes run. She moans around him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Up. Come on. I want you the other way now.</div></div><span id="cascade-b2-beat-10"><<linkreplace "Stand still for it.">><p>His hand goes flat on her stomach and down, and two fingers find her cunt already wet, in to the knuckle, the heel of his palm hard on her clit until her cunt grips down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There. I remember that. That never was for show, whatever else was.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Let him.">><p>He turns her by the hip and puts her over the end of the bed one-handed, because the other one still has the glass in it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Stay like that. God. Yes — like that.</div></div><span id="cascade-b2-beat-12"><<linkreplace "Let him have it.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_lockup_crate_t5"] to ($game_state.media_cycle["sex_mercer_lockup_crate_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_lockup_crate_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_lockup_crate_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_lockup_crate_t5/c73b1a72c92.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_lockup_crate_t5/ca0a90e2b47.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_lockup_crate_t5/ca644e68baa.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_lockup_crate_t5/cd9ba54840d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He gets his cock into her and starts up unhurried, one hand spread flat on the small of her back out of old habit. Her cunt takes the whole thick length of him the way it always did, and she moans into the blanket.</p><span id="cascade-b2-beat-13"><<linkreplace "Take it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There. There she is. Not one thing about this has changed, and in the state I'm in that is worth more to me than the floor ever was.</div></div><p>He fucks her steady, no hurry anywhere in it, and her cunt answers the way it always has.</p><span id="cascade-b2-beat-14"><<linkreplace "Let him talk.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> That glass cost more per pane than this whole row of stalls is worth. I signed for every one of them. I signed for you the same week. Did you ever know that?</div></div><p>He doesn't wait to find out. He never has.</p><span id="cascade-b2-beat-15"><<linkreplace "Let him lean.">><p>He shifts his weight and puts his free hand flat on the crate beside her coat, and leans on it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> The plants woman. Thursdays. I never learned her name either, and it has started to bother me at night.</div></div><span id="cascade-b2-beat-16"><<linkreplace "Wait.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> His hand has been flat on that crate a while now. It's the stillest part of him.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Are you listening. You always did let a man get to the end of a thing.</div></div><span id="cascade-b2-beat-17"><<linkreplace "Let him have your ass.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_print_anal_t5"] to ($game_state.media_cycle["sex_mercer_print_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_print_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_print_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_print_anal_t5/c2ff9766ca5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_print_anal_t5/c20dfe1e529.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_print_anal_t5/c95ae78cb46.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_print_anal_t5/cd52b8a5539.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He pulls out of her cunt and puts his cock in her ass instead, the way the evening always used to end. She opens for him out of two years of practice, and he does not rush that either.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There. That's the one I was thinking of.</div></div><span id="cascade-b2-beat-18"><<linkreplace "Let him finish.">><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_print_anal_finish_t5"] to ($game_state.media_cycle["sex_mercer_print_anal_finish_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_print_anal_finish_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_print_anal_finish_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_print_anal_finish_t5/c037160e284.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_print_anal_finish_t5/cc5bb5d54ad.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_print_anal_finish_t5/ce30fc9434b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_print_anal_finish_t5/cf08e100143.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>His cock goes deep in her ass and stays there while he cums, and lets a breath out like a man sitting down. His weight stays forward, on the hand on the crate.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Ah. That's better. That is the first quiet hour I have had in a month.</div></div><span id="cascade-b2-beat-19"><<linkreplace "Reach for it.">><p>She reaches down inside for the old pull. The thing that used to open a man at the base of the spine. It closes on nothing. Not a flicker. Whatever he is now, she cannot get at it.</p><span id="cascade-b2-beat-20"><<linkreplace "Then give him the thing you brought.">><p>She gets her coat off the crate and takes the case out of it. Grey, courier-grade, a reader plate let into the lid. She puts it in his hands while he is still doing up his belt.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It's bonded. You have to open it yourself.</div></div><span id="cascade-b2-beat-21"><<linkreplace "Let him have it.">><p>He turns it over twice. Nobody has sent him anything since the floor went, and it takes him a moment to work out what is happening to him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Bonded. God. I used to sign for forty of these a week and never once opened one myself.</div></div><span id="cascade-b2-beat-22"><<linkreplace "Let him talk himself down.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> It was never the money. I want to be clear about that. It was never once about the money.</div></div><p>He says it to the box, not to her.</p><span id="cascade-b2-beat-23"><<linkreplace "Watch him open it.">><p>He spreads his palm flat on the plate, holds it there, and the reader goes warm and takes him. The lid gives. He lifts the bottle out and does not look at the box again.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You liked that floor. You are the only one left I can say that to.</div></div><span id="cascade-b2-beat-24"><<linkreplace "Pick up the empty.">><p>The case goes on the floor by his foot the way anything does once it's open. She folds it under her arm on her way past, tidying up after a man who has stopped tidying up after himself.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Leave it, leave it. God, you don't have to do that.</div></div><p>His cum runs out of her ass and down her thigh and she leaves it. He sits back with the bottle in his fist, pleased with it, and doesn't put it down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Thursday. It doesn't have to be Thursday. Come whenever. You know where the door is now.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Thursday.</div></div>[[Get your coat.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_owner_print">>
<<set $game_state.current_node = "cap_owner_print.base">>
<<script>>setup.markCanvasTriggered("cap_owner_print");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_owner_print.base") === -1) { vn.push("cap_owner_print.base"); }<</script>>
<<script>>advanceTime(90);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "case_held", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "owner_print_taken", "set");<</script>><p>He is most of the way through the one about the car and the driver when he stops.</p><span id="cascade-b1-beat-0"><p>He sets the glass down on the crate and doesn't pick it back up. Outside, somebody drags a shutter down and swears at it.</p><span id="cascade-b1-beat-1"><<linkreplace "Wait.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> I never had to ask you for anything. Not once in two years. I'd think of it and it would be done, and I never gave that the credit it was owed.</div></div><p>He says it the way a man says a fact about the weather.</p><span id="cascade-b1-beat-2"><<linkreplace "Say his name.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Mercer.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Mm.</div></div><p>He doesn't correct her. He doesn't lower his voice, and he doesn't look at the door.</p><span id="cascade-b1-beat-3"><<linkreplace "Let him get to it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> It was a good arrangement. Say what you like about the rest of that place. That part of it worked, and it worked for both of us, whatever anyone down here would tell you.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Watch his hand.">><video src="./videos/scenes/mercer_hands_on_t4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>His hand comes over and settles on her thigh, above the knee, with the whole weight of it behind it. Not a grab. The way a man rests a hand on something of his.</p><span id="cascade-b1-beat-5"><<linkreplace "Don't move.">><p>She doesn't move. He never looks up to see whether she will.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You've not changed. That's the thing about you. Everything else went and you didn't, and I find I need that more than I'd like to.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Where was I. The driver. I never did learn the man's name.</div></div><p>He picks it up exactly where he put it down, and his hand stays where it is.</p>[[Sit it out.->Location_mercer_room]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "rung_mercer_hands_on">>
<<set $game_state.current_node = "rung_mercer_hands_on.base">>
<<script>>setup.markCanvasTriggered("rung_mercer_hands_on");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_mercer_hands_on.base") === -1) { vn.push("rung_mercer_hands_on.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "mercer_hospitality_open", "set");<</script>><p>He holds the corner table like it is still an office. One hand on the glass, the other one out, explaining something to a room that did not ask.</p><<set _bp to random(0, 2)>>
<<if _bp is 0>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Sit down. I'll get you a. No. Right. You don't. Two years and I still reach for the second glass.</div></div>
<<elseif _bp is 1>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> The one at the bar in the good coat. Two months ago he had eleven people under him. Now he counts what's in his pocket before he orders. This room is full of us.</div></div>
<<else>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Man coming Thursday wants a badge history that stands up to a real check. He'll pay what I ask because there isn't a second person down here who can do it.</div></div>
<</if>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_mercer", "trait_key": "relation", "operator": "lt", "value": 6}]})>>
<p>He leans in, and the volume goes out of him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> The name. I did ask. I'm asking properly this time. Not in here, not where the room can hear it. It costs me if it travels, and it costs me more than you'd think.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Who would it travel to, Mercer.</div></div><p>He looks at the room for a second. Then he answers the question.</p>
<</if>>
<<set $game_state.current_canvas = "mercer_end_table">>
<<set $game_state.current_node = "mercer_end_table.base">>
<<script>>setup.markCanvasTriggered("mercer_end_table");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_end_table.base") === -1) { vn.push("mercer_end_table.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "add", 2.0, false, null);setup.showEffectNotification();<</script>>
[[Let him hold court.->Location_underworld_bar]]<p>A padlock through a latch, and the stall in front of it shuttered. The room is only his after the market goes dark. Eleven at night until eight, and he is somewhere else the rest of it. He keeps late hours now. Everyone down here does, and he has started calling it a preference.</p>
<<set $game_state.current_canvas = "mercer_room_offhours">>
<<set $game_state.current_node = "mercer_room_offhours.base">>
<<script>>setup.markCanvasTriggered("mercer_room_offhours");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_room_offhours.base") === -1) { vn.push("mercer_room_offhours.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Back into the market.->Location_underworld_market]]<img src="./videos/scenes/mercer_room_hub.webp" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>One bulb, a bed against the wall, a crate doing duty as a table. The bottle on it is better than the room.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "mercer_hospitality_open", "operator": "is_false"}]})>>
<p>He is up off the bed before the door is shut, moving the crate a foot to the left as if that made it a table.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Sit. Sit down. It's not what you're used to — neither am I, come to that, and I'd rather you saw it than heard about it.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "mercer_hospitality_open", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "parts_loop_open", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "part_installed", "operator": "lt", "value": 1}]})>>
<p>He doesn't get up now. He nods at the crate and goes back to the bottle, and the room arranges itself around him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There she is. Shut the door behind you. It's a market out there and half of it listens for a living.</div></div><p>Her seam is empty under the coat. The old dead socket, nothing seated in it. The part is still in her pocket, or still on Kess's bench, and it does not work from either.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "mercer_hospitality_open", "operator": "is_true"}]})>>
<p>He doesn't get up now. He nods at the crate and goes back to the bottle, and the room arranges itself around him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There she is. Shut the door behind you. It's a market out there and half of it listens for a living.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_mercer_room">>
<<set $game_state.current_node = "hub_mercer_room.base">>
<<script>>setup.markCanvasTriggered("hub_mercer_room");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_mercer_room.base") === -1) { vn.push("hub_mercer_room.base"); }<</script>>
<<nobr>>
<<link "Let him talk." "Canvas_hub_mercer_room_Node_talk">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Pour for him." "Canvas_hub_mercer_room_Node_pour">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "owner_print_taken", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_mercer_room:cc0') ? '' : 'unlocked-choice'">
<<link "Give him the evening." "Canvas_loop_mercer_lockup_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_mercer_room:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave him to it." "Location_mercer_room">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<set _bp to random(0, 3)>>
<<if _bp is 0>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Nine years on that floor. You know what the glass cost? Per pane. I know it per pane because I signed for it, same as I signed for you. A man remembers what he signs for.</div></div>
<<elseif _bp is 1>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> There was a woman came up Thursdays to do the plants. Plants. In a building that made its money out of other buildings. I used to think that was the whole point of the place.</div></div>
<<elseif _bp is 2>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> I had a car and a driver and I never once learned the driver's name. That wasn't cruelty, it simply never came up. Now I'd like to know it and there's nobody left to ask.</div></div>
<<else>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> They gave me a floor the week I was useful and took it back the week I wasn't. I don't hold it against them. I'd have done it faster, and I'd have done it on a Friday.</div></div>
<</if>><p>None of it is about her. He is lonely for the man who had a floor, not for her. She is the only piece of that left in the room.</p>
<<set $game_state.current_canvas = "hub_mercer_room">>
<<set $game_state.current_node = "hub_mercer_room.talk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_mercer_room.talk") === -1) { vn.push("hub_mercer_room.talk"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "add", 2.0, false, null);setup.showEffectNotification();<</script>>
[[Let it run.->Location_mercer_room]]<p>She takes the bottle off the crate and fills his glass. He watches her hand do it and doesn't thank her, because thanking her never was part of it.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_mercer", "trait_key": "relation", "operator": "lt", "value": 12}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> You don't have to do that. ...No, go on. It's nice to have it done properly for once. Down here a man pours his own and calls it independence.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_mercer", "trait_key": "relation", "operator": "gte", "value": 12}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Again. Go on. This is the only hour of my week that runs the way it's meant to, and I've stopped pretending that's a small thing.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_mercer_room">>
<<set $game_state.current_node = "hub_mercer_room.pour">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_mercer_room.pour") === -1) { vn.push("hub_mercer_room.pour"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_mercer", "relation", "add", 3.0, false, null);setup.showEffectNotification();<</script>>
[[Sit with him.->Location_mercer_room]]<img src="./videos/scenes/mercer_undertow.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The Undertow at this hour is corners and low talk. She is three steps in before she places the man at the end table.</p><span id="cascade-b2-beat-0"><p>Out of the grey suit, into something cheaper. Thinner in the face.</p><span id="cascade-b2-beat-1"><<linkreplace "Cross to him.">><p>He looks up on her second step and is out of the chair before she reaches the table.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Wren. Wren — look at you.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Let him look at you.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Sit down. Sit. What are you drinking. No, don't tell me. You don't. You never did.</div></div><p>He has hold of her arm above the elbow. He isn't checking her over. He is just holding on.</p><span id="cascade-b2-beat-3"><<linkreplace "Sit.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Two years I ran you and I never once saw you walk into a room I hadn't sent you to.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> I thought — well. Doesn't matter what I thought. You're standing there.</div></div><span id="cascade-b2-beat-4"><<linkreplace "Say his name.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Mercer.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Yes. Yes, all right.</div></div><p>Something crosses his face and settles again.</p><span id="cascade-b2-beat-5"><<linkreplace "Wait for it.">><p>He leans in. His voice comes down to the level the corners use.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Small thing. Nobody's called me that down here. It's Adler. Adler, all right? Humour an old man his fresh coat of paint.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Answer him.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What are you doing down here, Mercer.</div></div><p>He waits half a second for something to follow it. Nothing does.</p><span id="cascade-b2-beat-7"><<linkreplace "Watch him take it.">><p>Whatever he was going to do with that, he doesn't. He sits back and the pleasure comes straight back into his face, unbroken.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Business. Believe it or not.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Ask what business.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Stall on the market, back end of the row. I sell what I know, and it turns out I know a great deal.</div></div><span id="cascade-b2-beat-9"><<linkreplace "Let him tell it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Half the men down here are running from a floor of that tower and not one of them can read a manifest. I can read a manifest.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> I'm not poor. I want you to know that. I did all right out of it.</div></div><span id="cascade-b2-beat-10"><<linkreplace "Ask nothing.">><p>She doesn't ask. He tells her anyway, briefing her the way he used to. The same voice with the floor taken out from under it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> They cleaned that penthouse out in a day. One day. Nine years I was up there.</div></div><span id="cascade-b2-beat-11"><<linkreplace "Let him get to it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Come round. I've a room behind the stall. It's a concrete box, I won't pretend otherwise, but there's a bottle in it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Come and sit with me and we'll talk about when things were run properly. You'll come.</div></div><span id="cascade-b2-beat-12"><<linkreplace "Agree.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> All right.</div></div><div class="thought-bubble thought-bubble-npc"><div class="thought-bubble-content"><em>💭 Npc is thinking:</em> She notices that she said it twice and didn't stop when he asked. She files it with the readings and doesn't look at it again.</div></div><p>He is still talking when she looks down at his hands on the table. Big, soft, a signet he has stopped wearing and the pale band still on the finger.</p><p>She doesn't tell him why she came. She hasn't worked out yet how she takes it off him.</p>[[Leave him talking.->Location_underworld_bar]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_mercer_resurfaces">>
<<set $game_state.current_node = "cap_mercer_resurfaces.base">>
<<script>>setup.markCanvasTriggered("cap_mercer_resurfaces");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_mercer_resurfaces.base") === -1) { vn.push("cap_mercer_resurfaces.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "mercer_found", "set");<</script>><img src="./videos/locations/kess_berth.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>He has the key under the lamp when she comes down, and the file shut in a box beside it. He has been on the small thing, not the big one.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Come here. I've taken this as far as I can on my own.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Ask what he's got.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You said hardware you could beat.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I can. I have. I know what it wants now. It wants a handshake, and I know the shape of the handshake.</div></div><p>She waits for the part he's working up to.</p><span id="cascade-b2-beat-2"><<linkreplace "Let him narrow it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I've had everything off you I'm going to get. You're the receiver. You were never the hard half.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> The other end I can read, but I can't be it.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Hear the correction.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And I priced it wrong when I took it. I said a hand instead of the dead man's. Because everyone who signs a machine like you is dead by now.</div></div><p>He sets the key down and looks at her.</p><span id="cascade-b2-beat-4"><<linkreplace "The ask.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> He isn't. So it's the hand I need. His, warm, pressed flat and whole. Not a smudge off a glass. The kind a lock takes and keeps.</div></div><p>The bench is cold under her palm again. She leaves it where it is this time.</p><span id="cascade-b2-beat-5"><<linkreplace "Reach for the key.">><p>Her hand goes towards it and there is not much left to reach for. It is in four pieces on a cloth, with the lamp over the smallest one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It doesn't go anywhere. It hasn't been a whole thing since Tuesday, and the bit that matters is the bit I can't open.</div></div><span id="cascade-b2-beat-6"><<linkreplace "Say the other reason.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> And he'd know it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There you go. Whoever he is, he had it long enough to know it by the weight. Put that in front of him and you've told him everything about you in one go.</div></div><span id="cascade-b2-beat-7"><<linkreplace "Then how.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then how do I bring you a hand.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Bonded case. The market's full of them — courier boxes that only open to the buyer's hand and keep a record of it, because the record IS the receipt. Get him to open one. Bring me the case.</div></div><span id="cascade-b2-beat-8"><<linkreplace "Wait for the rest.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I don't need his name and I'm not asking for it. That's yours.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I need the hand, and I need him not to make a thing of it while it's happening.</div></div><p>He goes back to the lamp.</p><p>She has known the answer since the day he told her there was a key. She doesn't say it now either.</p><p>Somewhere down here is a man who signed for her, and she is going to go and find his hands.</p>[[Go and find him.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "kess_needs_print">>
<<set $game_state.current_node = "kess_needs_print.base">>
<<script>>setup.markCanvasTriggered("kess_needs_print");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_needs_print.base") === -1) { vn.push("kess_needs_print.base"); }<</script>>
<<script>>advanceTime(20);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "print_needed", "set");<</script>><img src="./videos/scenes/kess_file_shape.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She comes down the ramp and he keeps his eyes on the work. The file is open on the steel, weighted flat with a spanner at each corner, and he has been at it a while.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Don't touch the corners. I've got them where I want them.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Ask what he's got.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> You've read it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Some of it. Enough to tell you what it is, which isn't the same as what it says.</div></div><p>She stays standing. There is a stool a foot from her hip and she stays standing.</p><span id="cascade-b2-beat-2"><<linkreplace "Let him say it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's not a file. A file is one thing about one person. This is a programme — intake sheets, revisions, sign-offs, a whole office of people doing paperwork for years.</div></div><p>Her hand finds the edge of the bench and rests there, flat.</p><span id="cascade-b2-beat-3"><<linkreplace "Hear him rank it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I've stripped Vance freight, Vance medical, Vance security. I've seen their paperwork. It doesn't look like this. This is somebody's life work.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> How long.</div></div><p>The question comes out flatter than she means it to.</p><span id="cascade-b2-beat-4"><<linkreplace "Wait for the number.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Eleven years, start to last entry. The early sheets are handwriting. The late ones are printed. Somebody got funding.</div></div><p>Eleven years is a number she has nowhere to put. Her breathing doesn't change. Something under her sternum does.</p><span id="cascade-b2-beat-5"><<linkreplace "The index.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There's an index. Serials, one to a line, a lot of lines. They don't start at one — whoever began this was already carrying work over from somewhere else.</div></div><p>She looks at the column and does not count it.</p><span id="cascade-b2-beat-6"><<linkreplace "The two columns.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Two date columns against each serial. First one's filled all the way down. Second one's filled most of the way down.</div></div><p>He says it the way he'd read a gauge. Her hand has gone tight on the bench edge and she makes it let go.</p><span id="cascade-b2-beat-7"><<linkreplace "Look at the second one.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> One column for the day they started you. One for the day they stopped. Most of the second column is filled in.</div></div><p>She lets it stand. He wouldn't.</p><span id="cascade-b2-beat-8"><<linkreplace "Ask what it means.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Say what it means.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> No. I'm telling you what's on it. What it means is a thing people decide, and I've been wrong about people.</div></div><p>That is as close to gentle as he comes.</p><span id="cascade-b2-beat-9"><<linkreplace "Hear the rest.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Huh. Here's the thing I've been chewing on. Every page in this opens for me. Intake, revisions, sign-offs. All of it reads.</div></div><p>He turns one page over with two fingers and lays it flat.</p><span id="cascade-b2-beat-10"><<linkreplace "Let him finish.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> One page doesn't. Yours. Same seal as the key. On one sheet, in a stack where nothing else is locked at all.</div></div><p>Somebody went through a finished programme and shut one page. She feels the cold of the bench come up through her palm.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> So it rides the key, like I said. I open that, you get your page. Until then, this is all there is.</div></div><p>She stays a moment longer than she needs to, then straightens off the bench and goes to find work for her hands.</p>[[Leave it with him.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_file_shape">>
<<set $game_state.current_node = "cap_file_shape.base">>
<<script>>setup.markCanvasTriggered("cap_file_shape");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_file_shape.base") === -1) { vn.push("cap_file_shape.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "file_shape_known", "set");<</script>><img src="./videos/locations/kess_berth.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Black water, the hull on its blocks, the smell of cut steel. Kess is at the bench with the cot behind him and her key somewhere under the mess he calls an order.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "leash_cut", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "gte", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Bed's paid and the line's on. I've a hull to cut and you've nothing in you that needs me. That is the first time that's been true.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "leash_cut", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "lt", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Line's off. You're nobody's asset now, which doesn't make the cot free. It makes it something you have to want.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "part_held", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You're paid up, so I'm on it. Don't hover.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "part_held", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You've come back empty, so it went. Sit down and tell me what it did before you go spending on the next one.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "part_held", "operator": "gte", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You've got something on you that came off a stall. Bring it here when you want it in. It's a bench job, not a doorway job, and you'll be face-down on the cradle for it.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "part_held", "operator": "lt", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Your key's where you left it. So's my hand. You've been sleeping rough. That buys you a floor, not me.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "part_held", "operator": "gte", "value": 1}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You bought the part. Good. I still don't seat hardware on a bench that isn't paid — take a proper night on the line first, then bring it back and I'll have it in you inside the hour.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_kess_berth">>
<<set $game_state.current_node = "hub_kess_berth.base">>
<<script>>setup.markCanvasTriggered("hub_kess_berth");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_kess_berth.base") === -1) { vn.push("hub_kess_berth.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "leash_cut", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_kess_berth:cc0') ? '' : 'unlocked-choice'">
<<link "Ask how the work's going." "Canvas_hub_kess_berth_Node_work">><<script>>setup.markChoiceVisited("hub_kess_berth:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "chip_read", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hub_kess_berth:cc1') ? '' : 'unlocked-choice'">
<<link "Ask about the chip." "Canvas_hub_kess_berth_Node_chip">><<script>>setup.markChoiceVisited("hub_kess_berth:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "spec_pending", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('hub_kess_berth:cc2') ? '' : 'unlocked-choice'">
<<link "Tell him the part failed." "Canvas_hub_kess_berth_Node_debrief">><<script>>setup.markChoiceVisited("hub_kess_berth:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "part_held", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('hub_kess_berth:cc3') ? '' : 'unlocked-choice'">
<<link "Give him the part." "Canvas_kess_install_part_Node_base">><<script>>setup.markChoiceVisited("hub_kess_berth:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sabin_drains_done", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "decoy_made", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('hub_kess_berth:cc4') ? '' : 'unlocked-choice'">
<<link "Have him make you a blank." "Canvas_kess_makes_the_blank_Node_base">><<script>>setup.markChoiceVisited("hub_kess_berth:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave him to it." "Location_kess_berth">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "gte", "value": 1}]})>>
<p>He turns the controller over under the lamp unasked. That is as close to an answer as he gets.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's a handshake, not a lock. It wants to hear a hand it knows. I'm learning what it listens for — off you, mostly, since you're the only receiver in the room.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Keep the line paid and I keep at it. That's the whole arrangement. You'll know when I've got something because I'll say so.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "feed_line_days", "operator": "lt", "value": 1}]})>>
<p>The key is exactly where it was last time, in the same tray, under the same rag. He hasn't had it under the lamp in days.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's going nowhere. I don't work a bench I'm not paid for. That's not me being hard, it's me still being here in a year.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Take a night on the line, proper, and I'll pick it back up. Crash rough all you like. That keeps you upright. It doesn't keep me interested.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Ten coin a night. The House pays that for one man. She files it where she files everything and goes to work.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_kess_berth">>
<<set $game_state.current_node = "hub_kess_berth.work">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_kess_berth.work") === -1) { vn.push("hub_kess_berth.work"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Leave him to it.->Location_kess_berth]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 2}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Nothing happened. He finished, I reached, and there was nothing there to push against.</div></div><p>Kess stops what he is doing, which he has not done for anything she has said before, and looks at the bench rather than at her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Nothing at all. That's the useful kind. A lock pushes back — yours didn't, so it isn't locking, it's listening. I shouted on the wrong wire.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Don't buy me another talkback. I want a sweep head. The flat ones off a salvage board, the kind that listens across instead of shouting the once. Ask him for a sweep.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "lt", "value": 3}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It found me. Something came down on it and shut it, hard, and I had to lie there with his weight on me and not make a sound.</div></div><p>He turns her round by the shoulder, unhurried, and reads the seam at the base of her spine with two fingers before he answers.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It bit you. That's not a safety — safeties fail open. That's a guard, and a guard means somebody's still using the thing.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Sweep was right and it got caught listening. So the next one takes the bite instead of you. An isolator, off the same tables. Small, heavy, and the man will tell you it's dead stock.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "mercer_attempts", "operator": "gte", "value": 3}]})>>
<div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It let go. Then something went down a list, found the hole where I am, and shut the door on its way back past me.</div></div><p>That is the first thing she has told him that he writes down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> A list. Then it was never keyed to a man at all. It's a set of voices, and his was one of them. That's why one answer was never going to be enough.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Last one, then. A stacked talkback — holds more than one voice at once. Bring me that and if it takes, there's nothing left in you that answers to anybody.</div></div>
<</if>>
<<set $game_state.current_canvas = "hub_kess_berth">>
<<set $game_state.current_node = "hub_kess_berth.debrief">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_kess_berth.debrief") === -1) { vn.push("hub_kess_berth.debrief"); }<</script>>
<<script>>advanceTime(15);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "part_spec", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "spec_pending", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Go and find it.->Location_kess_berth]]<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Still where you left it and still shut. I've had a light on it twice and I've learned the same nothing both times.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's not a thing you open. It's a thing somebody's paperwork opens. Your page came up because the two were cut together, and I'd want the rest of that paper before I went at it with anything sharp.</div></div>
<<set $game_state.current_canvas = "hub_kess_berth">>
<<set $game_state.current_node = "hub_kess_berth.chip">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_kess_berth.chip") === -1) { vn.push("hub_kess_berth.chip"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Leave it with him.->Location_kess_berth]]<img src="./videos/scenes/kess_berth_night.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The berth is where she left it. Black water, the stripped hull up on the blocks, Kess at the cradle with a torch in his hand. He takes her being back as given. He reads the topside off her the way he read the wrongness off her core, and goes still.</p><span id="cascade-b2-beat-0"><p>Before she says a word she pulls the file out and thumbs it open under his work-light. Because she has to know. She gets three pages in. Long enough to see her own designation on it, older than she is, and the word BUILD where a birth would go. Then the pages turn to garble: keyed, sealed, a wall dropped exactly where the answer starts.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> It's about her. It's the whole of her. And she can't read a line of the part that matters.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Put both on his bench.">><p>She sets two things down on the steel beside him: the sealed file, and the little controller she took off Mercer on the way down. Kess wipes his hands, picks up the controller, turns it in the light. Then he thumbs the file, sees the same locked garble, and sets them side by side like two parts off the same machine.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Huh. Same lock. This little key and that file are cut to the same hand — whoever sealed one sealed the other. Makes sense. Same people built you and wrote you up.</div></div><span id="cascade-b2-beat-2"><<linkreplace "Ask if he can open them.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Can you get into them.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Into the key, eventually. It's hardware, and hardware I can beat. Get that reading his hand instead of the dead man's and it cuts your leash from your side. The file rides on the same crack, so it opens when the key does. But it's not a night's work, and I don't guess at timelines on a thing that takes you with it if I'm wrong. It takes what it takes.</div></div><span id="cascade-b2-beat-3"><<linkreplace "Tell him the other problem.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then take the time. I've got nowhere to be. The Spire's shut over me. I can't go back up, and I can't be seen looking for a bed. I need somewhere down here. I'll pay for it. Coin, not favors.</div></div><p>Kess looks at the hull, at the cradle rigged for something bigger than a person, at her. Doing the sum a man does before he lets a problem sleep under his roof.</p><span id="cascade-b2-beat-4"><<linkreplace "Wait for his terms.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There's a cot by the feed line. It's not the box you're used to — half a charge if you're cheap, a full night on the line if you pay for it. You pay per night, in coin, and you keep your hands off my gear. Coin dries up, so does the arrangement. We clear?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Clear.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> A cot in a breaking-dock, rented by the night off a man who owes her nothing. It's the safest she's been in two years. Because for the first time the key to her is on a bench she can watch instead of in a pocket she can't reach. She'll pay his coin and wait him out. Down here, waiting is a thing she owns.</div></div>[[Set down. This is home now, for a while.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "kess_1b_open">>
<<set $game_state.current_node = "kess_1b_open.base">>
<<script>>setup.markCanvasTriggered("kess_1b_open");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_1b_open.base") === -1) { vn.push("kess_1b_open.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "berth_home", "set");<</script>><img src="./videos/scenes/salvage_verdict.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess closes the last panel and steps back, wiping his hands, and looks at Wren the way he'd look at a hull he's decided is finished. Not fixed. Finished.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> That's you operational. Leg holds, drain fires clean, core takes a charge without cooking itself. You're a weapon again. Congratulations.</div></div><span id="cascade-b3-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> But I told you there was something down there I didn't like. I had my proper look while I had you open. And here's the thing. It's not damage. Everything else they broke or wore out. This they built.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Built what.</div></div><span id="cascade-b3-beat-1"><<linkreplace "Hear it.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> A governor. A bad-tempered little piece of hardware seated under your core, older than the rest of you, wired so deep it's part of the frame. It's not there to run you. It's there to stop you. One specific thing you're built so you cannot do.</div></div><span id="cascade-b3-beat-2"><<linkreplace "What thing.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There's a man you can't point your teeth at. You read every other body I put on this cradle by the end. But the one who owns you, you couldn't drain him if he was open on this table in front of you. That's not you being loyal. That's not you being scared. That's this.</div></div><span id="cascade-b3-beat-3"><<linkreplace "Take it out, then.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Then take it out.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Can't. It's keyed — pull it blind and it takes you with it, and I don't do wakes. There's a controller for it somewhere. A key. Whoever holds it cuts it clean in a minute. I don't have it. You don't. Not my business whose it is.</div></div><span id="cascade-b3-beat-4"><<linkreplace "You already know whose.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He signs for me. He's held the key the whole time.</div></div><p>She leaves whose out of it. She already has the shape of the answer, and it's the shape of the man whose name is on her papers. The one who's spent every order she ever took knowing she could never turn and make him stop.</p><span id="cascade-b3-beat-5"><<linkreplace "Feel it settle.">><p>Something settles into place at the root of her that isn't comfort. She can feel exactly where it sits now. A locked thing, one door, and no key on her side of it. She'll carry it. A thing she can see is a thing she can carry.</p><span id="cascade-b3-beat-6"><<linkreplace "Settle up.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> We're square. You paid as you went, most don't. Go on. You've got a key to find.</div></div><span id="cascade-b3-beat-7"><<linkreplace "Stand up.">><p>She stands off the cradle. The leg holds, the drain sits true. For the first time she knows the exact shape of the thing that's owned her. Not a feeling, a component, with a key, and the key is somewhere she can walk to and take. That isn't despair. It's a map.</p><span id="cascade-b3-beat-8"><<linkreplace "And under that.">><p>And under that, further down, the name from the leak. The one syllable that fit her like a socket and then slipped. She still can't hold it. She's just stopped being able to stop reaching for it.</p>[[Go to work.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "salvage_verdict">>
<<set $game_state.current_node = "salvage_verdict.base">>
<<script>>setup.markCanvasTriggered("salvage_verdict");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_verdict.base") === -1) { vn.push("salvage_verdict.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "core_sealed", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "salvage_done", "set");setup.applyAndNotifyFlag("player", null, "mission_3_active", "set");<</script>><p>Wren's off the cradle, catching her breath, when Kess stops with his hand still in the open panel at the base of her spine. He's gone still the way a man goes still when the wrench finds a bolt that shouldn't be there.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Hold on.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There's something down here I don't like. Wired deeper than the rest of you — under the core, not in it. Older, too. It's not what's stopping the drain, so I've been working around it. But I want a proper look before I close you up for good.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What is it?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Don't know yet. That's what I don't like. Finish getting your teeth back, then we'll talk about it.</div></div>
<<set $game_state.current_canvas = "salvage_chip_snag">>
<<set $game_state.current_node = "salvage_chip_snag.base">>
<<script>>setup.markCanvasTriggered("salvage_chip_snag");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_chip_snag.base") === -1) { vn.push("salvage_chip_snag.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Later, then.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_12_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a last body waiting. A dock-hand, paid, unbothered. He looks steady this time. The readout in his hand is already half-green before Wren's even crossed the floor.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's warm. Warmer than it's ever read on my bench. This is the last one. I just need to see it hold under load. So turn it over, use him, and reach for the take at the finish.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> One clean pull and you're done. Don't fight it this time. Let it work.</div></div>
<<set $game_state.current_canvas = "salvage_session_12">>
<<set $game_state.current_node = "salvage_session_12.base">>
<<script>>setup.markCanvasTriggered("salvage_session_12");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_12.base") === -1) { vn.push("salvage_session_12.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_12_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_12_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The dock-hand's efficient. Bends her over the cradle, takes her from behind, sets a steady pace and holds it. "Strangest job I've had," he says over his shoulder, half a laugh. Kess doesn't answer. He's watching the needle sit flat and green.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Steady. It's not even flickering. Take him to the finish.</div></div>
<<set $game_state.current_canvas = "salvage_session_12">>
<<set $game_state.current_node = "salvage_session_12.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_12.n2") === -1) { vn.push("salvage_session_12.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_12_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_12_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes on her and she reaches. The old pull, down at the base of the spine. No cold socket this time, no clawing after a dead thing. His secrets walk out of him in one clean draw. It opens easy; the take barely costs her a want.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. Full pull, right through the finish, no strain on the readout at all. That's whole. That's a clean core.</div></div><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's trim now, holding under load. So. The other one, last time. Put it on him and mean it.</div></div><p>She levels the emitter at the dock-hand and keys it. The field rolls out full and even and drops over him like weather. He goes slack where he stands, eyes gone, a dead weight held up by nothing. Under, and staying under.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> That's it. Full field, clean drop. Both weapons live off one good core, and it's good now. You came in here with a dead drain and a dead emitter. You walk out with two.</div></div>
<</if>>
<<set $game_state.current_canvas = "salvage_session_12">>
<<set $game_state.current_node = "salvage_session_12.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_12.n3") === -1) { vn.push("salvage_session_12.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_12_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The dock-hand dresses, pockets his coin, lets himself out into the dark. Kess sets the readout down and leaves the probe where it is. Nothing left to chase down the seam.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You're done. I mean it. That's the last visit. The drive's back, the drain fires clean, and it held under load without a wobble. Operational.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Whatever they broke in you, it's mended. Get off my cradle and go find out what you can do with it.</div></div>
<<set $game_state.current_canvas = "salvage_session_12">>
<<set $game_state.current_node = "salvage_session_12.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_12.read") === -1) { vn.push("salvage_session_12.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.applyAndNotifyTrait("player", null, "emitter_broken", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle. Whole.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_11_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting. A dockside regular she's used before, paid up front, unbothered. He knows the shape of the job by now. Stands loose against the bench, waiting to be told nothing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's warm today. Warmer than it's been. So don't be careful with it — take him how you want him, top to bottom, all your call. I want the drive under load, not idling.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time. I think this one gives you something back.</div></div>
<<set $game_state.current_canvas = "salvage_session_11">>
<<set $game_state.current_node = "salvage_session_11.base">>
<<script>>setup.markCanvasTriggered("salvage_session_11");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_11.base") === -1) { vn.push("salvage_session_11.base"); }<</script>>
<<nobr>>
<<link "Take him." "Canvas_salvage_session_11_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_11_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She puts him down on the cradle and climbs on, sets the pace off her own hips. Slow, then flat and hard, exactly the rhythm she wants and not his. "Fine by me," he says, hands off, letting her. Kess watches the meter climb.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> That's it. Needle's moving — real charge this time. Don't stop, don't ease it. Run him.</div></div>
<<set $game_state.current_canvas = "salvage_session_11">>
<<set $game_state.current_node = "salvage_session_11.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_11.n2") === -1) { vn.push("salvage_session_11.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_11_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_11_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She wrings him dry and reaches. Down inside for the old pull that used to open a man at the base of the spine. This time it catches. It fires clean, full take, and the whole shape of him lays open in her hands.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There it is. Full pull, clean through the finish, no sputter. That's the weapon. That's you. Welcome back.</div></div><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Drain's clean now. Try the other one again — same as before, thumb it at him.</div></div><p>She keys the emitter at the regular. This time a field rolls off it, thin and stuttering. His eyes glass, his breath drags, his knees dip. Then it guts out and he catches the bench, swaying, still up on his feet.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. It drove that time. Weak, half a field, didn't put him down. But the core spilled into the second draw. Can't hold it yet. One more session and it lands full.</div></div>
<</if>>
<<set $game_state.current_canvas = "salvage_session_11">>
<<set $game_state.current_node = "salvage_session_11.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_11.n3") === -1) { vn.push("salvage_session_11.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_11_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The regular dresses and lets himself out, emptied and none the wiser, laid open and already forgetting it. Kess kills the readout and turns it around so Wren can see the line spike and hold.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Drive's seated. Drain's clean. Whatever seized in you, it's turning over on its own now. I don't have to nurse it anymore.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You came in here a wreck with a cold socket. You're walking out a weapon. Go use it on someone who matters.</div></div>
<<set $game_state.current_canvas = "salvage_session_11">>
<<set $game_state.current_node = "salvage_session_11.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_11.read") === -1) { vn.push("salvage_session_11.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle. Armed.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_10_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting. A big one this time, a dock-hand off the heavy cranes, broad and slow-moving. Paid, told nothing. He stands where he's put and says less, patient the way big men are.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's warm now. Last session it caught for a breath. This one it'll catch and hold, I think. So turn it over. Bend him to it, take him deep, work him proper.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time. I want to see how much of him you can pull.</div></div>
<<set $game_state.current_canvas = "salvage_session_10">>
<<set $game_state.current_node = "salvage_session_10.base">>
<<script>>setup.markCanvasTriggered("salvage_session_10");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_10.base") === -1) { vn.push("salvage_session_10.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_10_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_10_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She bends him to it. Takes him over the cradle, gets herself braced and open, and he feeds his cock into her cunt deep and unhurried, all that weight behind each stroke. "Tell me if it's too much," he says, low. She won't. Kess watches the meter.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Needle's climbing — good, that's the core drinking. Keep him deep, keep the seat full. Don't rush the stroke; the drain wants the whole finish, not a fast one. Let it build.</div></div>
<<set $game_state.current_canvas = "salvage_session_10">>
<<set $game_state.current_node = "salvage_session_10.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_10.n2") === -1) { vn.push("salvage_session_10.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_10_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_10_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes deep, spills up into her cunt, a long shudder of all that weight. She reaches down inside for the old pull, and this time it catches. Grabs.</p><p>The socket floods and takes. The shape of the man comes up her spine near whole. His years, his ledger, his quiet. Most of him, in one long draw.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There — there it is. Strong catch, socket flooding, meter near the top. That's nearly the full take; almost the whole man pulled off one finish. His years, his weight, all of it up the trace. That's the readout I wanted.</div></div><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> While he's still standing. That emitter of yours runs off this same core. If the drain's catching, the other one might wake too. Thumb it at him. Let's see.</div></div><p>She pulls the emitter, levels it at the spent dock-hand, and keys it. Nothing rolls off it. No field, no heat, no give. The big man just blinks at her, waiting. Dead weight in her hand.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Nothing. Figured as much. Core's barely driving the one draw. It's got nothing spare for a second yet. Leave it. It'll come back when the drain's all the way trim.</div></div>
<</if>>
<<set $game_state.current_canvas = "salvage_session_10">>
<<set $game_state.current_node = "salvage_session_10.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_10.n3") === -1) { vn.push("salvage_session_10.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_10_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The big one dresses slow and lets himself out, paid twice and lighter than he came, though he'll never know it. Kess pulls the readout and runs a thumb down the trace, nodding at what he sees.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Drive's nearly back. It caught strong and held near the whole way. That's a working weapon, just short of trim. You're one session from operational. Off, back, and this next one seals it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Come back when you've got coin for the last. One more finish and you walk out of here armed.</div></div>
<<set $game_state.current_canvas = "salvage_session_10">>
<<set $game_state.current_node = "salvage_session_10.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_10.read") === -1) { vn.push("salvage_session_10.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle — one to go.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_9_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting when Wren comes in. A talker, dockside, paid up front and already three sentences deep about the weather, the boats, his cousin's boat. The kind of man who fills a room to keep from thinking.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> This one runs his mouth. Good. The drain likes a man who's already leaking — easier to catch the thread and pull it. Core's warmer now. I think it'll hold this time.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> So turn it over, use him however you like. And reach for the take at the finish. If it catches, don't fight it. Let it walk a whole sentence out of him.</div></div>
<<set $game_state.current_canvas = "salvage_session_9">>
<<set $game_state.current_node = "salvage_session_9.base">>
<<script>>setup.markCanvasTriggered("salvage_session_9");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_9.base") === -1) { vn.push("salvage_session_9.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_9_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_9_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She leans back on the cradle and puts him where she wants him, and for once the mouth goes quiet. He works her cunt with his tongue, slow, hands spread on her thighs.</p><p>"Quiet one," he mumbles up at her between passes, half a laugh. "That's fair. Fair." Kess watches the meter, not them.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There — needle's twitching already. He's open. Keep him going. I want him spent when you reach for it.</div></div>
<<set $game_state.current_canvas = "salvage_session_9">>
<<set $game_state.current_node = "salvage_session_9.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_9.n2") === -1) { vn.push("salvage_session_9.n2"); }<</script>>
<<nobr>>
<<link "Take him inside." "Canvas_salvage_session_9_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_9_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She pulls his cock up into her cunt and rides it out, and when he empties she reaches. The old pull, down at the base of his spine. This time it grabs. Holds.</p><p>A word comes up through him and out his mouth like it was hers to take: "Nobody knows I sank the Marda. I cut her loose myself. For the coin." Then the thread drops.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There it is. Held right through the finish. A whole sentence, clean, true. He didn't even feel it leave. Good. That's the drain working.</div></div>
<<set $game_state.current_canvas = "salvage_session_9">>
<<set $game_state.current_node = "salvage_session_9.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_9.n3") === -1) { vn.push("salvage_session_9.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_9_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The talker dresses, running his mouth again. The weather, the boats. Never once wondering why he told a stranger the worst thing he'd ever done. He lets himself out. Kess is already behind her with the probe, reading the seam.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> That's the best pull yet. A full sentence, held clean through. The drive's nearly seated. Nearly there.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> One or two more and it'll hold on its own, no coaxing. Come back when you've got coin for the next.</div></div>
<<set $game_state.current_canvas = "salvage_session_9">>
<<set $game_state.current_node = "salvage_session_9.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_9.read") === -1) { vn.push("salvage_session_9.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_8_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a mark waiting. A dockside john she pulled off the coin-boards, shirt already off, sitting back on the bench like he owns the hour. He doesn't. He's meat with a pulse and a day in his head.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's warmer than last time. It'll turn over now — might even bite. Get on top of him. Run it your way, not his. You've done the lying-back work; I want you driving.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time. This one I think you catch.</div></div>
<<set $game_state.current_canvas = "salvage_session_8">>
<<set $game_state.current_node = "salvage_session_8.base">>
<<script>>setup.markCanvasTriggered("salvage_session_8");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_8.base") === -1) { vn.push("salvage_session_8.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_8_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_8_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She puts him on his back and climbs on, sets the pace herself. Slow, then hard when she wants it hard, hands flat on his chest to keep him down. "Strangest job on the coin-boards," he breathes, half-laughing. She doesn't answer. Kess watches the meter climb.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There it is — needle's live. Keep him going. Don't reach yet. Wait for the finish.</div></div>
<<set $game_state.current_canvas = "salvage_session_8">>
<<set $game_state.current_node = "salvage_session_8.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_8.n2") === -1) { vn.push("salvage_session_8.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_8_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_8_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He empties under her and she reaches. Down inside for the old pull, the thing that used to open a man and walk his secrets out. It catches. Weak, a flicker, but it grabs.</p><p>One thread of him comes loose. A wharf name, a crate he moved that morning, the low door behind it. Then it slips and guts out. Gone. But it fired.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> That. There. You felt that? It caught. Only a thread, only a scrap of his day, then it dropped. Doesn't matter. It fired. That's the first real take.</div></div>
<<set $game_state.current_canvas = "salvage_session_8">>
<<set $game_state.current_node = "salvage_session_8.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_8.n3") === -1) { vn.push("salvage_session_8.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_8_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The mark dresses, tosses her a look he can't name, and lets himself out into the dock-dark none the wiser he was read. Kess is already at the meter, thumbing back the spike, reading the shape of the catch.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Weak, yeah. Grabbed a scrap and lost the rest. But hear me. That wasn't a memory of the weapon. That was the weapon. The thing itself, live, doing its work. Everything before this was a dead socket. This wasn't.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It holds longer each time we run it. Costs you every visit. Come back with coin and we'll widen the catch — turn a thread into a whole man.</div></div>
<<set $game_state.current_canvas = "salvage_session_8">>
<<set $game_state.current_node = "salvage_session_8.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_8.read") === -1) { vn.push("salvage_session_8.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_7_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has the next one waiting. A hand off the freighters, weathered, silent, paid up front. He takes the job as it comes. Men who work boats that long stop asking.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's warmer than last time. You'll feel it try. It won't hold, but it'll try. And that's the part I need to watch. So turn it over. Use him however you like.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Push it this time. Don't be gentle with it.</div></div>
<<set $game_state.current_canvas = "salvage_session_7">>
<<set $game_state.current_node = "salvage_session_7.base">>
<<script>>setup.markCanvasTriggered("salvage_session_7");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_7.base") === -1) { vn.push("salvage_session_7.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_7_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_7_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He turns her, bends her over the bench, and works into her hard. No talk, no easing in, just a flat steady pound like he's done this his whole life. "Job's a job," he grunts once, and that's the only thing he says. Kess watches the readout, not them.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. Needle's twitching. It knows he's there. It just can't get a grip yet.</div></div>
<<set $game_state.current_canvas = "salvage_session_7">>
<<set $game_state.current_node = "salvage_session_7.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_7.n2") === -1) { vn.push("salvage_session_7.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_7_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_7_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes deep and she reaches. Hard, furious, willing the old pull to catch. It flickers. Something at the base of the spine stirs, the weapon coughing awake half a second. She drags at it and it dies anyway. Nothing walks out of him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Did you feel that? It lit. Half a beat, then it dropped. That's not dead. That's a bad connection.</div></div>
<<set $game_state.current_canvas = "salvage_session_7">>
<<set $game_state.current_node = "salvage_session_7.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_7.n3") === -1) { vn.push("salvage_session_7.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_7_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The hand pulls his trousers up and lets himself out, silent as he came in. Kess is already down behind her with the probe, chasing the flicker back along the seam, mouth tight.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You were angry. Good. That's what pushed it over the line far enough to light. Anger's fuel — don't apologize for it, use it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It sputtered because the driver's still weak, not because it's gone. We're close. Two, maybe three more and it holds through the finish. Come back with coin for the next.</div></div>
<<set $game_state.current_canvas = "salvage_session_7">>
<<set $game_state.current_node = "salvage_session_7.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_7.read") === -1) { vn.push("salvage_session_7.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_6_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting when Wren comes in. Younger than the others, quiet, first time by the look of him. Sitting too straight, hands flat on his knees, waiting to be told what to do.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> This one's green. He'll freeze if you leave it to him, so don't. Take him where you want him — slow to start, then hard. The drain's still faulting, but it caught a flicker last time. I want to see if it does it again.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Same as always. Reach whether it comes or not.</div></div>
<<set $game_state.current_canvas = "salvage_session_6">>
<<set $game_state.current_node = "salvage_session_6.base">>
<<script>>setup.markCanvasTriggered("salvage_session_6");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_6.base") === -1) { vn.push("salvage_session_6.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_6_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_6_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She takes it off his hands. Puts him on his back, works him in slow until the shake leaves him, then drops the pace and rides him hard. "Sorry — is that — am I doing it right," he manages, half a question. Kess keeps his eyes on the readout.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You're fine. Stop talking. There — needle just twitched. Keep her on him.</div></div>
<<set $game_state.current_canvas = "salvage_session_6">>
<<set $game_state.current_node = "salvage_session_6.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_6.n2") === -1) { vn.push("salvage_session_6.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_6_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_6_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes fast, gasping, hips jerking up into her. She reaches down inside herself for the old pull. This time something answers.</p><p>A thin thread of it opens at the base of his spine, holds a half-beat, sputters like a wet match. Then dies. But it held. Longer than nothing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. You feel that? It caught and ran a half-beat before it dropped. Last time was dead flat. That's not dead anymore.</div></div>
<<set $game_state.current_canvas = "salvage_session_6">>
<<set $game_state.current_node = "salvage_session_6.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_6.n3") === -1) { vn.push("salvage_session_6.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_6_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The boy dresses in a hurry, red to the ears, and lets himself out. Kess pulls a stool up behind Wren and sets the probe to the seam, reading the trace it left.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> The drive's coming back. It held longer that time because it's remembering how. The pathway's still there, just slow to open. Each pass it'll hold a little more before it gives.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Don't chase it hard, you'll tear the seam. Rest, let the strain drop, come back when you've coin for the next. We build it in half-beats.</div></div>
<<set $game_state.current_canvas = "salvage_session_6">>
<<set $game_state.current_node = "salvage_session_6.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_6.read") === -1) { vn.push("salvage_session_6.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_5_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting when Wren comes in. A courier off the fast boats, young, paid, mouthy about it. Jacket half off, grinning like he's already got the story he'll tell later.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> This one's a talker. Ignore it. Core's warmer than last time. You might get a flicker off him, might get nothing. That's what I'm here to see. So turn it over, use him however you like.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time. Whatever comes up, I want the reading.</div></div>
<<set $game_state.current_canvas = "salvage_session_5">>
<<set $game_state.current_node = "salvage_session_5.base">>
<<script>>setup.markCanvasTriggered("salvage_session_5");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_5.base") === -1) { vn.push("salvage_session_5.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_5_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_5_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The courier's got no patience in him. Spins her, bends her over the cradle, works into her hard and fast with his hands dug into her hips. "Best coin on the whole run," he says, breathless, cocky. "Gonna be back for this." Kess watches the meter, not them.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Save your breath, courier. The reading takes what it takes, whatever you feel about it.</div></div>
<<set $game_state.current_canvas = "salvage_session_5">>
<<set $game_state.current_node = "salvage_session_5.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_5.n2") === -1) { vn.push("salvage_session_5.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_5_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_5_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes hard inside her and she reaches down for the old pull. This time something answers. A flicker. The socket warms, half-catches, a fraction of the take opening at the base of his spine.</p><p>Then it drops. Gone before it's a thing. She felt it almost work. Worse than nothing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. There. It caught. Half a second, right through the finish, then it dropped. Did you feel that? That's not nothing. That's the first real one.</div></div>
<<set $game_state.current_canvas = "salvage_session_5">>
<<set $game_state.current_node = "salvage_session_5.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_5.n3") === -1) { vn.push("salvage_session_5.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_5_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The courier dresses, still grinning, and lets himself out with a line about coming back. Kess ignores him, already crouched behind Wren with the probe, chasing that half-second flicker down the seam before it goes cold.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It caught and it dropped. That's a driver waking up, not a dead one. The pull's still there. It just can't hold the charge long enough to walk anything out. Yet.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Feeling it half-work is the worst part. I know. But that flicker's the map back. Come back with coin and we chase it — next one, it holds longer.</div></div>
<<set $game_state.current_canvas = "salvage_session_5">>
<<set $game_state.current_node = "salvage_session_5.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_5.read") === -1) { vn.push("salvage_session_5.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_4_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting when Wren comes in. An old regular of his, already stripped, already on the cradle. Hands behind his head. He's done this before and it shows. Bored, easy, patient.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> This one's a regular. Knows the drill, won't spook, won't ask. Core's still cold. You'll pull nothing off him. But I want it turning over so I can read the driver.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> So turn it over. Use him however you like — ride him, finish him. And reach for the take at the finish. Every time. Eyes on the gauge.</div></div>
<<set $game_state.current_canvas = "salvage_session_4">>
<<set $game_state.current_node = "salvage_session_4.base">>
<<script>>setup.markCanvasTriggered("salvage_session_4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_4.base") === -1) { vn.push("salvage_session_4.base"); }<</script>>
<<nobr>>
<<link "Get on him." "Canvas_salvage_session_4_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_4_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She climbs on and takes him herself. Sets the pace, works him at a flat steady grind, nothing performed about it. "Same as always," he says to the ceiling. "Wake me if I'm needed." Kess keeps his eyes on the readout.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Keep it steady. I don't need him loud, I need him finishing. Watch the needle when he goes.</div></div>
<<set $game_state.current_canvas = "salvage_session_4">>
<<set $game_state.current_node = "salvage_session_4.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_4.n2") === -1) { vn.push("salvage_session_4.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_4_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_4_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He empties into her and she reaches. Down inside for the old pull, the thing that used to crack a man open at the spine and walk his secrets out. Nothing catches. Cold socket, dead as before.</p><p>But the gauge on Kess's readout twitches. Once. A single flick of the needle, then flat.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> There. You see that? Dead through the finish — no charge, no pull — but the needle moved. First time it's moved at all.</div></div>
<<set $game_state.current_canvas = "salvage_session_4">>
<<set $game_state.current_node = "salvage_session_4.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_4.n3") === -1) { vn.push("salvage_session_4.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_4_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The regular climbs off, dresses in silence, lets himself out the way he came. Kess is already crouched at the seam with the probe, chasing that one twitch back down the line, jaw set.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Still dead. Don't mistake me. You pulled nothing, and you won't for a while yet. But that flick? That's the driver taking a breath. It was flat as a stone last time. Now it's not.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> We're getting somewhere. Slow, and it costs you every visit. But somewhere. Come back when you've got coin for the next.</div></div>
<<set $game_state.current_canvas = "salvage_session_4">>
<<set $game_state.current_node = "salvage_session_4.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_4.read") === -1) { vn.push("salvage_session_4.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_3_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has another body waiting. A welder off the night shift, big through the shoulders, paid and told nothing. He stands there rolling his neck, impatient the way big men get when they're being kept from the work they came to do.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's still cold. You'll pull nothing off him — same as last time. But I've got a part to swap while it's turning, so keep it turning. Turn it over, use him however you like.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time. I want to watch it fail while I've got my hands in the seam.</div></div>
<<set $game_state.current_canvas = "salvage_session_3">>
<<set $game_state.current_node = "salvage_session_3.base">>
<<script>>setup.markCanvasTriggered("salvage_session_3");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_3.base") === -1) { vn.push("salvage_session_3.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_3_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_3_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>No easing about the welder. He bends her over the bench, gets a hand flat on her back and works into her hard and fast, all shoulder. "Quick job, then," he grunts, not asking. Kess ignores them, elbow-deep in the housing, prying a seized part loose.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Keep it turning. I've got the driver half out — don't stop till the finish.</div></div>
<<set $game_state.current_canvas = "salvage_session_3">>
<<set $game_state.current_node = "salvage_session_3.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_3.n2") === -1) { vn.push("salvage_session_3.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_3_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_3_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes deep and holds her there, spent. She does what Kess said. She reaches down inside for the old pull, the thing that used to break a man at the spine. Nothing to reach with. The socket's still cold, still empty.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Dead. Clean through the finish, no charge. And there it is, the part in my hand, seized solid. That's your fault. That's the whole fault.</div></div>
<<set $game_state.current_canvas = "salvage_session_3">>
<<set $game_state.current_node = "salvage_session_3.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_3.n3") === -1) { vn.push("salvage_session_3.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_3_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The welder pulls his coveralls up and lets himself out, paid twice and none the wiser. Kess turns the seized part over under the lamp, thumbing the pitting, almost pleased. The flat pleasure of a man who's finally cornered the thing he was chasing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's the soft driver. The coupling that feeds the drain. It's not broken, it's seized. Been binding for years and you never felt it because you had power to spare. Now you don't, so it reads dead.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Good news is I know what it is now. Bad news is it comes free slow, and it costs you every visit. Come back when you've got coin for the next.</div></div>
<<set $game_state.current_canvas = "salvage_session_3">>
<<set $game_state.current_node = "salvage_session_3.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_3.read") === -1) { vn.push("salvage_session_3.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_2_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has a body waiting when Wren comes in. A rigger off the night boats, paid, told nothing. Boots already off, easy about the wait.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Core's cold. You'll pull nothing off him. I know that. I need it turning over so I can find what's seized. So turn it over. Use him however you like.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time. I want to watch it fail. I need to see where the charge dies.</div></div>
<<set $game_state.current_canvas = "salvage_session_2">>
<<set $game_state.current_node = "salvage_session_2.base">>
<<script>>setup.markCanvasTriggered("salvage_session_2");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_2.base") === -1) { vn.push("salvage_session_2.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_2_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_2_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The rigger lays her back on the cradle, gets her legs up, works into her at a slow flat pace. "Strangest coin I've earned," he says. "Not the worst."</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Quiet. She's not here for you. Pressure's building at the base. I can see it load. That's the driver waking. Keep steady.</div></div>
<<set $game_state.current_canvas = "salvage_session_2">>
<<set $game_state.current_node = "salvage_session_2.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_2.n2") === -1) { vn.push("salvage_session_2.n2"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_2_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_2_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He empties into her. She reaches down inside herself for the old pull. The thing that used to open a man at the base of the spine. Nothing answers. A cold socket where the weapon sat.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Dead. Right through the finish. No charge, no pull, nothing. The socket's there, the driver just won't turn it over. Good. Clean data.</div></div>
<<set $game_state.current_canvas = "salvage_session_2">>
<<set $game_state.current_node = "salvage_session_2.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_2.n3") === -1) { vn.push("salvage_session_2.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_2_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The rigger dresses and lets himself out, paid twice and none the wiser. Kess crouches behind her with a probe, chasing the fault down the seam.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> It's not the drain. Drain's fine. It's the thing that drives it that's gone soft. And that I can bring back. Slow. Costs you every visit. Come back when you've got coin for the next.</div></div>
<<set $game_state.current_canvas = "salvage_session_2">>
<<set $game_state.current_node = "salvage_session_2.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_2.read") === -1) { vn.push("salvage_session_2.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<img src="./videos/scenes/salvage_session_1_t4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess has the first one waiting when Wren comes in. A dock hand off the cargo runs, paid, told nothing. Big through the shoulders, half-stripped, easy about the coin and the quiet.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> First body. Don't expect anything off him — the take's dead, I know it's dead. But I can't read a drain that isn't turning over, and yours has been cold since they hauled you in. So turn it over. Use him however you like — rough, slow, doesn't matter to me, only to the readout.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And reach for the take at the finish. Every time, hard as you can. I want to watch exactly how it fails. The shape of the failure tells me what's left to fix.</div></div>
<<set $game_state.current_canvas = "salvage_session_1">>
<<set $game_state.current_node = "salvage_session_1.base">>
<<script>>setup.markCanvasTriggered("salvage_session_1");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_1.base") === -1) { vn.push("salvage_session_1.base"); }<</script>>
<<nobr>>
<<link "Get to it." "Canvas_salvage_session_1_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_1_fuck_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He bends her over the lip of the cradle, one hand flat on her back, and works into her from behind at a steady loading-dock pace. "Cleanest coin I've made all season," he says to no one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Save your breath for the work. She's a bench, not a date. Steady pace — good, I can read steady. Watch her spine, right at the base, where the seam sits. That's the only part of her I care about.</div></div>
<<set $game_state.current_canvas = "salvage_session_1">>
<<set $game_state.current_node = "salvage_session_1.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_1.n2") === -1) { vn.push("salvage_session_1.n2"); }<</script>>
<<nobr>>
<<link "Keep going." "Canvas_salvage_session_1_Node_leak">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Somewhere in the steady of it her spine trips. Not arousal, a fault. Something older loads behind her eyes with no place to put it. Smoke. Not this dry-dock's oil-smoke. The kind that doesn't wash out of a person.</p><p>A bigger hand than the dock hand's. It doesn't hunt for the seam. It goes straight to the socket at the base of her spine, like it set the socket there, like it knew the map before there was a map.</p><p>A voice says a word over her. Not the kind said over a thing someone owns. The kind said over a person. And under it, off the edge of hearing, one syllable of a name. It fits her like a socket she never knew was empty.</p><p>She reaches for the rest of it, the way Kess told her to reach for the take. It goes out like a held breath let go. Gone. Just the dock hand's hands again, and the cold.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> ...who.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> You said something. Don't chase it — whatever that was, it's not on my readout, so it's not the job. The name, the smoke, none of it. Reach for the take instead. Now, while he's close.</div></div>
<<set $game_state.current_canvas = "salvage_session_1">>
<<set $game_state.current_node = "salvage_session_1.leak">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_1.leak") === -1) { vn.push("salvage_session_1.leak"); }<</script>>
<<nobr>>
<<link "Reach for the take." "Canvas_salvage_session_1_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/salvage_session_1_finish_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He empties into her and she does what Kess said. She reaches down inside herself for the old pull, the thing that used to open a man at the base of the spine and walk his secrets into her hands. Reaches, and closes on nothing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Dead. Right through the finish — no charge, no pull, flat line the whole way. A cold empty socket where the weapon used to sit. Good. That's clean data, though — the first clean thing I've got off you.</div></div>
<<set $game_state.current_canvas = "salvage_session_1">>
<<set $game_state.current_node = "salvage_session_1.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_1.n3") === -1) { vn.push("salvage_session_1.n3"); }<</script>>
<<nobr>>
<<link "Let him go." "Canvas_salvage_session_1_Node_read">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The dock hand dresses, pockets the second half of his coin, and lets himself out none the wiser. Kess crouches behind her with the probe, tracing the drain-seam by feel. He stops, thumb resting on the ridge of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Huh. This seam was re-seated. By hand. Someone had their fingers in here before me. And they didn't have to look for the socket, they went straight to it. No field-medic did this. A field-medic gropes around for it. Whoever closed you up already knew exactly where it lived.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Anyway. It's not the drain — drain's sound. It's the thing that drives the drain that's gone soft, and that I can bring back. Slow. Costs you every visit. Come back when you've got coin for the next one.</div></div>
<<set $game_state.current_canvas = "salvage_session_1">>
<<set $game_state.current_node = "salvage_session_1.read">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_session_1.read") === -1) { vn.push("salvage_session_1.read"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", -8.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_session", "add", 1.0, true, null);setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 0.0, true, null);setup.showEffectNotification();<</script>>
[[Off the cradle.->Location_kess_berth]]<p>The torch is cold on its hook and the cradle sits empty, the hull up on its blocks going nowhere. Kess keeps hours like any other working man. Ten in the morning to ten at night, and not a minute either side. The black water under the walkway lies flat. Come back when he's cutting.</p>
<<set $game_state.current_canvas = "berth_offhours">>
<<set $game_state.current_node = "berth_offhours.base">>
<<script>>setup.markCanvasTriggered("berth_offhours");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("berth_offhours.base") === -1) { vn.push("berth_offhours.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Back up the ramp.->Location_underworld_strip]]<img src="./videos/locations/kess_berth.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Kess is where he always is, up in the guts of something with a torch. He keeps working when Wren comes down the ramp. Just tips his chin at the cradle, and at the coin-box bolted to the bench beside it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Box first, then the cradle. Same as always. No coin, no session — go make some and come back.</div></div>
<<set $game_state.current_canvas = "salvage_repair_hub">>
<<set $game_state.current_node = "salvage_repair_hub.base">>
<<script>>setup.markCanvasTriggered("salvage_repair_hub");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_repair_hub.base") === -1) { vn.push("salvage_repair_hub.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 10}])>>
<<link "Pay the box and get on the cradle. (10 coin)" "Location_kess_berth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "repair_armed", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -10, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Pay the box and get on the cradle. (10 coin)">Pay the box and get on the cradle. (10 coin) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 10}])>>)</span><br>
<</if>>
<<link "Not today." "Location_underworld_strip">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><img src="./videos/scenes/kess_berth_intro.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The berth's colder than the strip, all cut steel and sparks, the red light of the underground shut out behind a hull. Someone's up on the work-cradle with a torch. It cuts out when Wren's boots hit the floor.</p><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> Yard's shut. Turn around.</div></div><span id="cascade-b3-beat-0"><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> ...that's Vance plate under the coat. No. I don't touch company work — company work touches back. Out.</div></div><p>He's already turning back to the hull, done with it.</p><span id="cascade-b3-beat-1"><<linkreplace "Name the fault.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I can't operate. Something in the core.</div></div><p>The word core turns the man's head. He comes down off the cradle, a gauge already in his hand, and holds it to the base of Wren's spine.</p><span id="cascade-b3-beat-2"><<linkreplace "Let him read it.">><div class="dialog-block dialog-npc"><div class="portrait portrait-placeholder"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg></div><div class="dialog-content"><strong class="dlg-inline">Stranger</strong> ...that's not a Vance core. That's not anybody's core I've got a book for. Bespoke. Hand-built. Somebody made you one at a time.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> I'm Kess. Sit down.</div></div><span id="cascade-b3-beat-3"><<linkreplace "Hear the terms.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Here's how it runs. I don't fix a thing like you in one sitting. I open you, work one thing, make it hold, close you up. Then you come back and we go again. Session at a time, however many it takes.</div></div><span id="cascade-b3-beat-4"><<linkreplace "Ask the price.">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> What's it cost.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Coin. Not company scrip. I can't spend Vance money without Vance noticing, and neither can you. Ten a session, and you're on the cradle.</div></div><span id="cascade-b3-beat-5"><<linkreplace "Hear the catch.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> And it's up front — every session, before I open you. You're broke, I can read that off you too, so you'll be earning it up the strip between visits — the House, the Pit, whoever's paying. No coin, no session. That part's yours.</div></div>[[So that's the deal.->Location_kess_berth]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "salvage_kess_intro">>
<<set $game_state.current_node = "salvage_kess_intro.base">>
<<script>>setup.markCanvasTriggered("salvage_kess_intro");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_kess_intro.base") === -1) { vn.push("salvage_kess_intro.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "kess_met", "set");<</script>><img src="./videos/scenes/salvage_waterfront_dawn.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The phone in her hip buzzes before the light's full up. Mercer's summons. The pattern she answers on reflex, before she's decided anything. She gets her feet under her to go in and report. The bad leg folds and puts her down on one knee.</p><span id="cascade-b2-beat-0"><p>The other road, then. Renner's depot, cheap hands, the cover she can still wear. She reaches back for the drain to check it's seated, and it answers cold. A dead click where the charge should catch. Nothing takes.</p><span id="cascade-b2-beat-1"><<linkreplace "Take stock.">><p>Both roads want a body that works. Hers doesn't. The leg holds if she never asks it to turn; the drain seats but won't fire; the core sits wrong behind her sternum, a low fault she can feel the edge of and can't reach.</p><span id="cascade-b2-beat-2"><<linkreplace "Consider the company.">><p>The company fixes assets. She knows exactly what fixing is: the techs open her up on the bench, find the fault, and take her back to spec.</p><span id="cascade-b2-beat-3"><<linkreplace "Count what that costs.">><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Back to spec is back to nothing. The four words go. The name that fit a lock she didn't know she had. Filed, overwritten, gone.</div></div><p>And she finds she does not want that. She does not look at why.</p><span id="cascade-b2-beat-4"><<linkreplace "Let it ring.">><p>So she doesn't call it in. The summons rings out unanswered. The first order in her life she's let go dark. No one's watching. No one will know until it's already done.</p><span id="cascade-b2-beat-5"><<linkreplace "Go off the books.">><p>There's underworld talk of hardware worked off the books: a ship-breaker down past the gate, in the underground, who takes machines the company can't see and asks the wrong questions for the right coin. The berth's down there, off the strip. She goes to find it.</p>[[Go find it.->Location_the_waterfront]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "salvage_body_wont_hold">>
<<set $game_state.current_node = "salvage_body_wont_hold.base">>
<<script>>setup.markCanvasTriggered("salvage_body_wont_hold");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("salvage_body_wont_hold.base") === -1) { vn.push("salvage_body_wont_hold.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "salvage_entered", "set");<</script>><p>She comes back a little at a time, into a room that has changed. The men are gone. The near door stands open on an empty corridor. The frame she was strapped to is on its side where somebody knocked it going out fast. She is on the floor by the grate they meant to hose her over, and her left leg will not answer, and the light under her skin is out. Properly out, not flickering, dark the way a cooled coal is dark.</p><p>Through the wall, two men are arguing.</p><p>One of them is Bastien. She would know that voice anywhere now, and it has not changed. Flat, unhurried, reasonable, a man explaining a position he sees no reason to raise his voice about. The other voice she has never heard in her life, and it goes through her wrong, because it is furious, and the fury has something under it she has no file for. It takes her a long muddled moment to find the word for the thing under it, and the word she finds is grief, and that makes no sense at all, because nobody has ever once been angry on her account, let alone torn up about it.</p><p>She is too far gone to hold any of it. The words come apart before they reach her. Four get through the whole of it and no more. One is Bastien's, and it is a word she knows the shape of because it is a word men use about her: an ownership word, said the way you'd say the price of a thing. And three come across in the other voice, and one of those three is a name. She is nearly certain it is a name. It goes into her somewhere below the amputation and fits, the way a key fits the one lock in a house that was left, a lock she did not know she had, and she cannot for her life say what the name was or why a stranger saying it should make the empty places in her ache like frostbite coming warm. And the last word, in that same broken voice, is one that has no business anywhere near a room like this, a word you say over a grave and not over a thing you are haggling for. She reaches for all four of them and they slide out of her hands.</p><p>The arguing stops. Not trails off. Stops, the way it stops when one man has said the thing there is no answer to.</p><p>Then the door. The far one, off its hinges already. He comes in, and she cannot make him hold still. He is a shape against the bad light and a smell of old smoke, and he crosses the room fast and goes down on one knee beside her, and she flinches, because everyone who has knelt beside her in this room has done it to use her. He doesn't. He turns her, careful of the dead leg, the way you'd turn something you already knew the weight of, and he finds the seam at the base of her spine without looking for it. No searching, his hand going straight to it in the dark like a hand going to its own pocket. He puts the weight back.</p><p>The drain seats home. She feels it take, feels the terrible backed-up pressure behind her sternum find, at last, the door it has been beating on, and begin to bleed off, slowly, down a channel that is hers again. It is not relief. It is too late for relief. But it is the difference between a thing that is failing and a thing that is going to fail, and her leg, somewhere very far away, twitches once and remembers most of itself.</p><p>He is already up. Whatever he came to do, it was not to talk to her; or he cannot; or there is no time. He puts two fingers against the side of her face for exactly as long as it takes to be sure she has come back, and even that is not a stranger's touch, and then he is a shape in the doorway and then he is gone, and she is alone in a broken room with her weapon back in her spine and no idea on God's earth why any of it just happened.</p><p>She wakes on the waterfront at dawn. Sore, and not whole. The fault sits in her core where it stopped and does not move, and she already knows, the way you know a scar before you've seen it, that it is not going to move again. But the drain is in its socket. Her leg carries her. The city is exactly where she left it, indifferent, the gulls going and the tide out, Mercer's work waiting and Renner's depot waiting and Sunday coming around again the way Sunday does.</p><p>And four words she cannot hold, and cannot stop reaching for, and one of them a name that fit a lock she didn't know was hers.</p>
<<set $game_state.current_canvas = "captivity_cain">>
<<set $game_state.current_node = "captivity_cain.base">>
<<script>>setup.markCanvasTriggered("captivity_cain");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("captivity_cain.base") === -1) { vn.push("captivity_cain.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "emitter_broken", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "captivity_done", "set");<</script>>
[[Get up off the dock.->Location_the_waterfront]]<p>It doesn't happen the way she has been bracing for. There is no tearing, nothing gives, no part of her comes off in anyone's hand. What happens is quieter and much worse: the charge fills the last of the room it has, and then it keeps coming, and there is simply nowhere left for it to be.</p><p>The man in her feels it before she does. Feels the whole housing of her go rigid under him, feels the hum climb past anything a body makes. He is already scrambling back off the frame when the light goes. Not out. Up. Every seam of her, every port and plate and the long empty line of the socket Bastien stripped, all of it comes up white at once through the skin, so that for a moment she is lit from the inside like a room with the lamp knocked over, and the men are on their feet and against the walls and one of them is saying oh Christ oh Christ and none of it reaches her.</p><p>Because inside, where she has spent her whole life being quiet, it has finally gone loud. Every door she was built with is open at once. Everything the company filed away where she couldn't reach it is standing in the light. Not memories, she has no memories, only the shape of the places they were cut out of, a hundred hollows all shrieking the same note. She has been a thing that feels nothing but the sex it's used for. She feels this. She feels all of it, for one white unsurvivable second, the entire amputated size of herself, and there is no word in her for what it is except that it is hers and they took it.</p><p>Then the safeties she doesn't own throw themselves, the way a station drops its own breakers before the fire, and it all goes black from the top down. The light under her skin dies. The hum falls out of the air. Her held-open eyes lose the ceiling.</p><p>The last thing that reaches her, from very far away, is the sound of a door coming off its hinges. Not the men's door. The far one, the one that has never once opened while she was awake.</p>
<<set $game_state.current_canvas = "captivity_break">>
<<set $game_state.current_node = "captivity_break.base">>
<<script>>setup.markCanvasTriggered("captivity_break");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("captivity_break.base") === -1) { vn.push("captivity_break.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "captivity_broken", "set");<</script>>
[[Go dark.->Location_captive_room]]<video src="./videos/sex/cell_he_does_not_stop_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>There's a line of them and it hasn't thinned. Someone's got her by the hips on the concrete and is working into her cunt at a flat, bored pace, and the man before him left her open and slick enough that it goes easy. That isn't the part they've stopped watching for. Under her sternum the plate has started to stutter. Light coming up between her ribs in pulses, off-time with the fucking, a dull red that wasn't there when they started and won't settle back down. Every load one of them put in her ticked it higher. It has nowhere to go. She's lit from the inside like something left switched on.</p><p>The socket at the base of her spine sits empty. A dry seam in the metal where the drain used to seat. That was the part that took. Stripped out, there's only the filling: cock after cock stacking charge behind the plate with no line out, and the readout on her chest climbs while the man fucking her doesn't notice, chasing his own thing, watching her tits move with it. The glow throbs up out of her skin and nobody backs off. They just wait their turn and fill her hotter.</p><p>'The fuck is she doing, she's lighting up.'</p><p>'Who cares, she's still tight. Go, go, you're up.'</p>
<<set $game_state.current_canvas = "cell_use_he_does_not_stop">>
<<set $game_state.current_node = "cell_use_he_does_not_stop.base">>
<<script>>setup.markCanvasTriggered("cell_use_he_does_not_stop");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_he_does_not_stop.base") === -1) { vn.push("cell_use_he_does_not_stop.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_he_does_not_stop_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_he_does_not_stop_a_crew_man_balks_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The one in her cunt pulls out mid-stroke. Not finished. He just steps back off her, cock still hard and shining, staring at the light going through her ribs like it's finally reached him what he's been putting himself into. She keeps twitching where he left her, hips still tipped up because nobody told them to come down. The glow pulses again, brighter, and something under the plate makes a sound. A thin electric whine climbing pitch. It's the machine, not her, because her face hasn't changed at all. Her face stopped changing a while back.</p><p>He backs another step and won't go near her again, cock going soft in his fist, looking around at the others like one of them's going to explain it. None of them do. The whine keeps rising out of her chest and the red bar under her sternum flickers, gutters, catches. A light with a short in it. Still she lies open on the floor the exact way the last man left her, ass up, thighs slack, waiting to be used by whoever's next.</p><p>'Boss. Boss, that's. That's not right.'</p><p>'Whatever the fuck she is, that ain't it working. That's it breaking.'</p><p>'She's glowing, man, look at her chest, I'm not putting my dick back in that.'</p>
<<set $game_state.current_canvas = "cell_use_he_does_not_stop">>
<<set $game_state.current_node = "cell_use_he_does_not_stop.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_he_does_not_stop.n2") === -1) { vn.push("cell_use_he_does_not_stop.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_he_does_not_stop_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Bastien crosses the floor unhurried and crouches at her chest to look. Not at her face, at the readout, at the number climbing behind the flicker. He watches it the way he watches everything about her: like a figure going into a ledger. He lays two fingers flat on the plate, feels the heat coming off it, the whine buzzing up through the metal into his hand, and he doesn't pull them away. He turns his head and looks at the man who stepped back, then at the rest of them standing there with their cocks out, gone uncertain.</p><p>Then he takes his fingers off the plate, wipes the heat off on her tit, and stands, and tells them to get back in her. He's not curious out loud. He's curious in the eyes. But his mouth is only cruel, and the two don't argue with each other in him.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> 'It's not breaking. It's filling. There's a difference and I've been watching it fill for a while now.'</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> 'You fuck her, it charges her. And somebody pulled the one part off her that let her spend it. So now it just goes in. Stacks up. Nowhere out. That's what the light is.'</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> 'Which means if she comes apart, I finally get to see what they built her out of. And there's exactly one way to reach that number. So finish. All of you. Back in her.'</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> 'She doesn't get to keep it, and she doesn't get to hold anything back either. Fill the filthy machine till it can't take another drop.'</div></div><p>'You heard him. Turn her over.'</p>
<<set $game_state.current_canvas = "cell_use_he_does_not_stop">>
<<set $game_state.current_node = "cell_use_he_does_not_stop.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_he_does_not_stop.n3") === -1) { vn.push("cell_use_he_does_not_stop.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_he_does_not_stop_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_he_does_not_stop_used_past_failure_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>They turn her over. Someone hooks her by the ankle and folds her onto her front, and she goes where she's put. Arms loose under her, cheek flat to the concrete. Then there's weight across her back and someone's in her ass now, driving hard the second the boss said go. Her legs stay where they set them, knees shoved apart, ass tipped up, because she's stopped bracing, stopped everything that isn't the plate. And it's her ass. The socket right there above the crack, dead and empty, the drain that used to take pulled out of it. Nothing takes now. Every thrust into her only feeds the thing that fills. The red bar between her ribs has stopped pulsing and gone solid, a level rising, and each grunt and each load somebody empties into her walks it up toward the top.</p><p>One of them reaches under her and works her clit rough while the man behind fucks her, because the boss said the fast way is to make her come. When it wrenches through her the readout jumps three marks at once and something under the plate flares white. It isn't pleasure on her at that point. It's overflow with no drain, and it burns; the charge climbing through her with nowhere to be, cooking her from the plate out. She makes a sound she hasn't made before. Thin, mechanical, wrong. They laugh and hold her down and drag it out of her again.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> 'Make her come. That's what moves it. Anyone can just fuck her. I want her spiking.'</div></div><p>'There it goes. You see it jump? Do it again, rub her out.'</p><p>'Hold her, hold her, she's going, she's fucking going—'</p><p>'Look at that light, it don't stop where the last one did.'</p>
<<set $game_state.current_canvas = "cell_use_he_does_not_stop">>
<<set $game_state.current_node = "cell_use_he_does_not_stop.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_he_does_not_stop.n4") === -1) { vn.push("cell_use_he_does_not_stop.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_he_does_not_stop_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/scenes/cell_he_does_not_stop_the_read_out_the_break_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The readout reaches the top of its climb and stops. Not because they've stopped. There is no higher left for it to go. The bar under her sternum is full end to end, a hard flat line of light burning through the skin between her ribs, too bright now to look at straight. The whine has gone past sound into a pressure you feel in your teeth. Everywhere else she's dark: face slack, eyes open on nothing, body still moving only because the man behind her is still moving it, hips still working her onto him out of habit and weight. Every small resistance the machine ever had is gone at once, given up together.</p><p>Bastien stands over the top of her head watching the plate, not her, the way he has the whole time. Charged to the top. No socket. No out. Something in her has to give with all that light and nowhere for it, and under the flat glare of the full readout it does. A man is still emptying into her ass and does not even notice.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> 'There. Top of the gauge. Now we find out what they were hiding in you.'</div></div><p>'Boss — boss, it's not moving anymore, it's just—'</p>
<<set $game_state.current_canvas = "cell_use_he_does_not_stop">>
<<set $game_state.current_node = "cell_use_he_does_not_stop.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_he_does_not_stop.readout") === -1) { vn.push("cell_use_he_does_not_stop.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -14.0, true, null);setup.showEffectNotification();<</script>>
[[Take the last of it.->Location_captive_room]]<video src="./videos/sex/cell_stutter_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The mattress lost its sheet a long stretch ago. She's face-down on the bare ticking, hips hauled up, and the man behind her has both hands clamped on her waist, fucking into her cunt at a flat bored pace. The pace of a thing he's used long enough to stop looking at. He isn't working for it. He's just emptying himself into a hole that's been left open for him.</p><p>Under her sternum the plate that used to burn clean white sits dim now. A dull ember guttering through her skin with every shove, the charge stacked so high behind it that it's stopped glowing right. Each time his cock bottoms out, the readout over the plate strobes and climbs another notch. Nobody in the room is bothering to read it yet. They will.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Look at it take that. Filthy machine doesn't even need telling anymore. Just lies there and lets itself get bred.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Barely lit. Whole thing's running on fumes. Good.</div></div>
<<set $game_state.current_canvas = "cell_use_stutter">>
<<set $game_state.current_node = "cell_use_stutter.base">>
<<script>>setup.markCanvasTriggered("cell_use_stutter");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_stutter.base") === -1) { vn.push("cell_use_stutter.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_stutter_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_stutter_her_leg_dies_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>It goes between one thrust and the next. Her left leg is braced, taking her weight on the knee. It simply stops. The muscle lets go all at once, the joint unlocks, and the leg slides out flat across the ticking, dead weight, slack from hip to heel. No twitch. No shudder back to life. It just quits.</p><p>Her hip drops crooked with nothing under it holding the line, and the man's next stroke shoves her sideways across the mattress because half of what used to brace her isn't answering anymore. Somewhere under the skin a thing that was supposed to keep working has gone dark and stayed dark, and the rest of her body keeps getting fucked around the failure like it never happened.</p>
<<set $game_state.current_canvas = "cell_use_stutter">>
<<set $game_state.current_node = "cell_use_stutter.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_stutter.n2") === -1) { vn.push("cell_use_stutter.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_stutter_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_stutter_he_keeps_going_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He doesn't stop. He barely slows. Just reaches down, catches the dead leg under the knee, and hooks it up over his forearm to get the crooked hip back where he wants it. Then he fucks her exactly as before, harder if anything, the slack limb swinging loose off his arm with every drive of his cock like a thing that's already been thrown out.</p><p>The rest of the room watches a machine's leg give out and does the only arithmetic that matters to them: it's still a hole, and the hole still works. Nobody moves to stop it. Nobody would. They lean in closer instead, to see.</p><p>"Its fuckin' leg just died. Keep going, keep going, don't you dare stop!"</p><p>"Leg's dead, hole's not. Who cares."</p><p>"Ride it till the next bit falls off."</p>
<<set $game_state.current_canvas = "cell_use_stutter">>
<<set $game_state.current_node = "cell_use_stutter.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_stutter.n3") === -1) { vn.push("cell_use_stutter.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_stutter_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/scenes/cell_stutter_bastien_leans_in_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Bastien comes off the wall and crouches at the edge of the mattress, close, elbows on his knees, watching the dead leg swing where it hangs off the man's arm. Not her face. Her face has never been the thing. He watches the failure. He reaches out and pushes two fingers deep into the slack meat of her thigh, testing, feeling for a tone that isn't there anymore, and something moves behind his eyes that has nothing to do with mercy.</p><p>He's interested. He's always most interested when a part of her stops. He keeps his fingers buried in the dead muscle a moment longer than he needs to, thumb pressing, reading her by hand while the man's cock keeps working her hole two inches away.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There it goes. Left side's dropping out — right on the number I said it would.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Don't you fucking stop. I want to see what quits next.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Look at that. Bought a machine, and it's coming apart while it gets used. Beautiful.</div></div>
<<set $game_state.current_canvas = "cell_use_stutter">>
<<set $game_state.current_node = "cell_use_stutter.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_stutter.n4") === -1) { vn.push("cell_use_stutter.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_stutter_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/scenes/cell_stutter_the_read_out_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>On the sternum plate the readout has climbed again. One more increment, logged the second the man's pace picked back up. Every stroke into her stacks a little more charge behind a plate that has nowhere left to send it. The socket at the base of her spine sits empty and cold, a dead port in the small of her back that nothing plugs anymore. That is where the drain used to bleed it off, where anal used to take something out of a man instead of pour it into her.</p><p>The number does not fall. It has never once fallen. Bastien's eyes go straight to it and stay there. Not on the swinging leg, not on the crew, not on her. On the count. He takes out the little book and writes the new figure under all the others, unhurried, while behind the number the plate flickers like it's finally getting tired.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Higher. Every time it fails, the number still climbs. That's the part they never believe.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Keep filling it. It's got nowhere to put any of it.</div></div>
<<set $game_state.current_canvas = "cell_use_stutter">>
<<set $game_state.current_node = "cell_use_stutter.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_stutter.readout") === -1) { vn.push("cell_use_stutter.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -14.0, true, null);setup.showEffectNotification();<</script>>
[[Stay where she's dropped.->Location_captive_room]]<video src="./videos/sex/cell_overflow_legs_held_open_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The crew are already in the room when it starts. No unwrapping, no chair pulled up slow. That part's over, she's been stripped since before they came in. Two of them take a leg each and fold her open on the mattress, a knee pinned to the concrete on either side, a forearm braced across each thigh, a hand clamped on each ankle. She's spread and she's held and nothing's inside her yet.</p><p>That's the point of holding her first. What they're about to do works better if she can't close on it, so they get her open and locked before a single cock touches her. The plate under her sternum reads high enough today to be worth the trouble, and every man in the room knows what a high reading means: she's easy to push over now, and pushing her over is the whole job.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Hold her open. I want the reading clean when she goes.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Look at it. A machine that fills up like a cheap whore and can't even spill what's in it. Bought and paid for, and it doesn't even work.</div></div><p>"Get the legs. Spread the filthy thing wide."</p><p>"It can't even close, look at it, it's just held there."</p><p>"Stay still, hole. You're gonna want to be real still for this."</p>
<<set $game_state.current_canvas = "cell_use_overflow">>
<<set $game_state.current_node = "cell_use_overflow.base">>
<<script>>setup.markCanvasTriggered("cell_use_overflow");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_overflow.base") === -1) { vn.push("cell_use_overflow.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_overflow_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_overflow_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>A man kneels into the gap they've made her hold and pushes into her cunt, and he doesn't fuck her so much as work her. A thumb set on her clit, a rhythm picked cold, not to get himself off but to get her off, because that's the order he was given. They're not here to come in her. They're here to make her come. A forced orgasm spikes the readout harder than anything else they can do to a body like hers, and every man in the room has learned that now, and they're grinning at it.</p><p>She holds against it because there is nothing else left to do with her hands full and her legs locked, and it doesn't matter. The machine comes when it's made to. He works her over the edge with the flat patience of a man doing paid work, and behind her sternum something starts to climb toward the wall it always finds now.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Make her spill. Doesn't matter what the thing wants. A machine comes when it's made to, and the number jumps every time it does.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There. Force it out of her. That reading's worth twice what just fucking her is. So make the filthy thing come, and mind you get it all the way.</div></div><p>"Come on, machine, give it up."</p><p>"Look at it fight. It doesn't want to, that's the best part."</p><p>"Doesn't matter what it wants, does it. Push it over."</p>
<<set $game_state.current_canvas = "cell_use_overflow">>
<<set $game_state.current_node = "cell_use_overflow.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_overflow.n2") === -1) { vn.push("cell_use_overflow.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_overflow_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_overflow_it_hurts_the_overflow_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>And she comes, and it's wrong. The charge goes off behind her sternum and slams into a wall that only her kind of body has. The heat that used to run out through the drain at the base of her spine has nowhere to run, so it turns and runs back up into her chest and stacks on top of the last load, and the coming stops being pleasure halfway through and becomes a fault firing down a line. She screams. Not the noise a whore makes on cue. A real one, torn out of her, the sound of a thing overloading with the vents shut.</p><p>The crew think it's the funniest thing they've seen all week. She screamed coming, and it clearly hurt her, and that just makes them want another one out of her. Someone's laughing hard enough to lean on the wall.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> That's the overflow. No channel. It's got nowhere to put itself, so it puts it in her. Scream all you want, filthy thing. The number is what I paid for, and the number is all I read.</div></div><p>"Ha. Hear that? It hurts it! It hurts the machine to come!"</p><p>"It's crying, look. Do it again, make it scream again."</p><p>"Whores don't scream when they come, sweetheart. You're broke."</p><p>"Doesn't even work right and we're still using it."</p>
<<set $game_state.current_canvas = "cell_use_overflow">>
<<set $game_state.current_node = "cell_use_overflow.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_overflow.n3") === -1) { vn.push("cell_use_overflow.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_overflow_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_overflow_they_keep_going_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>It changes nothing. They take turns on her. One pulls out and the next kneels straight in, her cunt then her ass by turns, and every load that goes into her adds a step to the thing stacked behind her sternum and takes nothing back out. The socket at the base of her spine sits empty through all of it. The one thing that ever drew any of this back out of her, stripped clean and gone. Her ass isn't a drain any more, it's just another hole that fills her. It only ever adds now. Nothing leaves.</p><p>Bastien has dragged his chair up close. He is not watching her face, or her cunt, or the man buried in her. He is watching the plate under her sternum, where the light has stopped sitting steady and started to climb and hold, and he is writing the number down in a book propped on his knee, checking it against her chest between loads the way a man reads a gauge that's running hot.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Keep her going. It stacks. Nothing comes back out of a machine with its drain pulled, so pour it all in.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Filthy overfilled thing. You'll take every one of them and hold every drop, and the reading goes up each time. That's all you're for now.</div></div><p>"Next. Get in the hole, it can't spill."</p><p>"Fill it right up, it's got nowhere to put it."</p><p>"Passed round like it's nothing, this one. It takes it every time."</p>
<<set $game_state.current_canvas = "cell_use_overflow">>
<<set $game_state.current_node = "cell_use_overflow.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_overflow.n4") === -1) { vn.push("cell_use_overflow.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_overflow_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>When they finally leave her spread and slack on the mattress, the plate under her sternum is not doing what it did before they started. The light in it has stopped being steady and gone to a pulse, higher than she has ever seen it read, and it stays there. It sits there, lit, climbing on nothing, with no drain to bleed it off.</p><p>Bastien crouches over her and looks at it. Only at it. He reads the number, writes the number, and the number is the whole reason he came. It went up. It does not go down. Out of everything that was done to her in this room, that is the one thing that changed, and it is the only thing in here that he counts as changed at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There's the reading. Higher than the last. You're closer now, machine. And every hole they put in you drives it up another notch and it never once falls.</div></div>
<<set $game_state.current_canvas = "cell_use_overflow">>
<<set $game_state.current_node = "cell_use_overflow.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_overflow.readout") === -1) { vn.push("cell_use_overflow.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -14.0, true, null);setup.showEffectNotification();<</script>>
[[Come down off it.->Location_captive_room]]<video src="./videos/sex/cell_frame_strapped_into_the_rig_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The frame is bolted to the floor before she's brought to it. A waist-high steel jig with a padded bar and cuffs at the four corners, built to hold something down while it gets worked on. They don't wrestle her into it. They set her. Fold her over the bar, feed her wrists into the cuffs, wrench the strap across the small of her back and crank it until she's fixed face-down at the exact angle they want, ass up, knees spread by the frame's own geometry, the empty socket at the base of her spine sitting open to the room.</p><p>Not held down. Positioned. Locked to spec, like a part dropped into a machine that's about to run. No hands needed once the straps bite, because a fixture doesn't get to move. Someone tests it with a shove and she doesn't shift an inch. The frame takes it for her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Bolt it down. I don't want the machine wandering off while it does its job.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Ass up, hole open, spine to the ceiling. That's the only shape it's good for now. So lock it there and leave it.</div></div>
<<set $game_state.current_canvas = "cell_use_frame">>
<<set $game_state.current_node = "cell_use_frame.base">>
<<script>>setup.markCanvasTriggered("cell_use_frame");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_frame.base") === -1) { vn.push("cell_use_frame.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_frame_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_frame_positioned_tuned_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>A crank on the side of the frame lifts the bar an inch; a boot hooks her knee and drags it wider until the cunt and the empty ass sit at the height a standing man wants. A fist takes her hair and tips her head off the frame to clear the throat, lets it drop, tips it again. Checking the line. They talk over her the whole time, the way men talk over a bench they're setting up. Not to her. About her.</p><p>Someone works two fingers into her ass and spreads, eyes the angle, wipes the hand off on her thigh. Someone else thumbs her cunt open, lets it close, satisfied. Nobody asks if she's ready because ready isn't a setting the rig has. Tuned. Zeroed. Set to spec and left waiting at the height of the line.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Zero the readout before anyone touches it. I want a clean count off this run. Every load logged, none of it wasted.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Height's good. Now it's just a hole at the right elevation. Start the line.</div></div><p>Bring her up an inch. I'm not squatting for a machine.</p><p>There. That's the height. Lock it.</p><p>Spread's good. Both holes on the same level, take your pick.</p><p>Wipe your hand on it, it's not gonna complain.</p>
<<set $game_state.current_canvas = "cell_use_frame">>
<<set $game_state.current_node = "cell_use_frame.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_frame.n2") === -1) { vn.push("cell_use_frame.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_frame_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_frame_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Then they run her. One after another down the line. Cunt, then ass, then whichever's nearest, no order to it, the frame absorbing every shove so she never moves off her mark. Each one fucks until he's finished and then stays, buried to the root, leaning his weight down on the small of her back to catch his breath, using her like a place to rest before he pulls out and the next steps up into the gap. Nobody talks to her. She's the bench they're all taking a turn on.</p><p>And every load that goes in lands with nowhere to go. The socket at the base of her spine sits empty where the drain used to bolt in. The ass that used to TAKE something out of a man now just filling, over and over, the drain inverted. Each one that gets held in her feeds the plate under her sternum. The charge stacks behind it and climbs, and the readout ticks and does not drop.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> That's it — hold it in when you're done. Every one you leave sitting in there winds the number tighter than the fuck did.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Don't rush the line. It's not going anywhere. It's a fitting.</div></div><p>Furniture with a hole. Best kind.</p><p>Move. My turn. And don't pull out slow, leave it in there for the meter.</p><p>Still tight after all that? Machine earns its keep.</p>
<<set $game_state.current_canvas = "cell_use_frame">>
<<set $game_state.current_node = "cell_use_frame.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_frame.n3") === -1) { vn.push("cell_use_frame.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_frame_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_frame_held_inside_marks_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>One of them doesn't pull out at all. He drives in to the root and stops, grinds her down flat onto the bar and just holds there. A full beat, two, hips flush to her ass. His hands go to work on everything else. A fistful of hair cranks her head back off the frame. The other hand wraps her throat from behind and squeezes until the readout jumps, then lets go and leaves the print of every finger behind on her skin.</p><p>He slaps the ass he's still buried in, hard, twice, watches the handprint bloom red and stay. Digs his thumbs into her hips until they bruise, marking his grip where the next man can see it. By the time he finally pulls out she's covered. Handprints across both cheeks, choke-marks coming up at her throat, drool dried on her chin, thumb-bruises on her hips. A machine handled rough and left marked all over, so anyone in the room can read exactly where it's been.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Choke it while you're seated in. The readout spikes when it can't breathe — fastest way to run the number up is to make the thing come while it's strangling.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Mark it up. I want to be able to see everywhere it's been, from across the room.</div></div><p>Look at that print come up. Take a picture.</p><p>Leave your grip on it. Save the next guy a handhold.</p>
<<set $game_state.current_canvas = "cell_use_frame">>
<<set $game_state.current_node = "cell_use_frame.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_frame.n4") === -1) { vn.push("cell_use_frame.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_frame_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>When they're finally done and the frame's cranked back and she's left bent over it. Dripping, marked, still bolted to spec. The only thing in the room still doing work is the plate under her sternum. The readout glows in the dim, and the number on it is higher than it was. A lot higher. It climbed with every load that got held in her and it did not come back down, because there is nowhere for it to go.</p><p>Bastien crouches at the front of the frame to read it. Not her face. The number. He watches it settle, holds a light to it, writes it down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Up again. Big jump off this run. It takes it in and it can't give any of it back. That's the whole trick of the thing.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Nowhere near topped out. Log it, reset the frame. We're not done running numbers off it.</div></div>
<<set $game_state.current_canvas = "cell_use_frame">>
<<set $game_state.current_node = "cell_use_frame.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_frame.readout") === -1) { vn.push("cell_use_frame.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -12.0, true, null);setup.showEffectNotification();<</script>>
[[Let them unstrap her.->Location_captive_room]]<video src="./videos/scenes/cell_turns_the_queue_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>By the time she's down on her knees in the middle of the concrete, the crew's already strung out along the wall in a loose line, waiting their turn like it's a thing they've done before. Bastien stays out of the line. He hauls the chair round so it faces the whole row of them, sits, and clicks a timer open in his palm. His cock's already out. His eyes are on the plate under her sternum, not on her.</p><p>'Thirty a man to start,' he says to the room. 'Move her down the line, don't crowd. I want to see how fast this thing climbs when you keep it fed.' The first man's already got a fist in her hair, waiting on the word. Bastien thumbs the timer. 'Go.'</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Thirty a man. Don't crowd her. I want it steady, not a pile-on. Not yet.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Look at it. Bought and paid for, and it takes a line better than a turnstile.</div></div><p>'Fuckin' finally. Been standing here with it out.'</p><p>'Save some, she's not going anywhere.'</p><p>'It's got more holes than the three of us need. Line moves.'</p>
<<set $game_state.current_canvas = "cell_use_turns">>
<<set $game_state.current_node = "cell_use_turns.base">>
<<script>>setup.markCanvasTriggered("cell_use_turns");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_turns.base") === -1) { vn.push("cell_use_turns.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_turns_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_turns_passed_down_the_line_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The first one fucks her mouth till he's done and pulls out to finish across her cheek, and before she's coughed it clear the next man's already stepping up and turning her by the jaw. Mouth, then cunt, then mouth again. Whoever's up takes whichever hole he wants and the crew calls it out while they wait. One holds her hips and fucks her through it kneeling; the next just wants her face and uses it. Nobody waits for her to be ready. Ready was never on the list.</p><p>It stacks on her and in her as it goes. Cum on her cheek, roped off her chin, a load left in her cunt that the next man just shoves back up into her with his own. By the fourth turn she's slick and dripping and the line hasn't even thinned. Bastien clicks the timer over at every swap and reads the plate, not her face, calling the number out loud like a man calling races.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Next. Don't be gentle. It gets you the same number.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There it goes. Half a point a load. Keep it moving, it's finally earning its keep.</div></div><p>'Turn it round, I want the cunt.'</p><p>'Swallowed that one. Good little hole.'</p><p>'Hurry up, I'm not done looking at what I'm getting.'</p>
<<set $game_state.current_canvas = "cell_use_turns">>
<<set $game_state.current_node = "cell_use_turns.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_turns.n2") === -1) { vn.push("cell_use_turns.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_turns_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_turns_t5.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Someone gets tired of the line and bends her over a knee, spreads her ass open with both thumbs, and works into the one hole that used to do the taking. He fucks it rough and finishes deep and doesn't pull out till he's soft. And that's the joke of her nobody in the room knows: the drain lived here once, at the base of her spine, and the ass was the thing that TOOK something out of a man. The socket's stripped now. Empty. So it only fills her. The drain run backwards, a load in the ass that goes nowhere but up.</p><p>Someone else reaches under and works her clit while the first man's still buried in her, mean and deliberate, forcing her over whether she wants it or not. When she clenches and comes the plate jumps, a hard tick, faster than any load did. Bastien sees it. 'There,' he says. 'That's the one that moves it.' He writes the number down. The charge climbs with nowhere left to go, and the stripped socket at the base of her spine does nothing at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> In the ass. That's where the good reading is. Trust me on that one.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There. Forced, it spikes. Make the machine come, don't just fuck it — climbs twice as fast.</div></div><p>'Rip that little hole open, watch it just take it.'</p>
<<set $game_state.current_canvas = "cell_use_turns">>
<<set $game_state.current_node = "cell_use_turns.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_turns.n3") === -1) { vn.push("cell_use_turns.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_turns_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_turns_used_and_pissed_on_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>By the time the line's thinned she's a mess on the floor, leaking out of both holes, cum drying tight on her tits and her face. One of them steps up like it's his turn again, but he stays soft. He just plants his feet over her, takes his cock in his hand, and pisses on her instead. Down her chest, into her open mouth, across the plate under her sternum, hosing off what the others left like she's a thing you rinse and not a person.</p><p>The crew loses it. Someone tips her chin up by the hair so it runs across her face and she has to hold it. Nobody stops him. When he's done he shakes it off on her and steps back into what's left of the line, and she kneels there in the wet of it, dripping, used up, a thing to empty into and onto and nothing more.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Christ. Fine. It rinses off same as anything else. Doesn't move the number, though. Do that on your own time.</div></div><p>'Open up, machine. Waste not.'</p><p>'Look at it just take that too.'</p><p>'Rinse and reuse, boys.'</p>
<<set $game_state.current_canvas = "cell_use_turns">>
<<set $game_state.current_node = "cell_use_turns.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_turns.n4") === -1) { vn.push("cell_use_turns.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_turns_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/scenes/cell_turns_the_read_out_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>When the last of them steps back the room goes quiet except for her breathing. Bastien crouches in front of her. The only time he gets close. He wipes the plate under her sternum clean with his thumb so he can read it. The number's higher than when they started. A lot higher. It went up with every load and it jumped with the ones they forced, and it hasn't shed a single point, because there's nothing left in her that lets it.</p><p>He looks at it a long moment. Not at her. Through her, at the reading, the way you'd check a gauge creeping toward a line you drew yourself. He clicks the pen and writes it down. He caps it. He doesn't look at her face once.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Higher than the last count, and it didn't drop a point. Nothing drains out of you anymore, does it. Good.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Faster than I thought. We'll do this again before it's had time to sit.</div></div>
<<set $game_state.current_canvas = "cell_use_turns">>
<<set $game_state.current_node = "cell_use_turns.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_turns.readout") === -1) { vn.push("cell_use_turns.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -12.0, true, null);setup.showEffectNotification();<</script>>
[[Wait for the next one.->Location_captive_room]]<p>The bolt drags back and for once it isn't just him in the gap. He holds the door open with one hand and lets three of them file past his shoulder into the cell, then crosses to the chair against the wall and sits, one ankle up on his knee, the notebook already open on his thigh. The three spread out around her the way men spread out around something cornered. Looking, deciding what she is before a single hand's on her.</p><p>That's where she stops being a person. Three sets of eyes, three sets of hands, and the one in the chair who only wants the number after.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Go on. She's bought and paid for. There's nothing in there you can wear out that I'm precious about.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Mind the plate on her chest, though. I want to read it when you're done with her.</div></div><p>'This the one? Christ.'</p><p>'They really do build 'em with a hole for everything.'</p>
<<set $game_state.current_canvas = "cell_use_first_three">>
<<set $game_state.current_node = "cell_use_first_three.base">>
<<script>>setup.markCanvasTriggered("cell_use_first_three");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_first_three.base") === -1) { vn.push("cell_use_first_three.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_first_three_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_first_three_manhandled_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>They don't wait for him to finish talking. A fist knots in her hair and turns her by it; another catches her wrists and wrenches them back; a third checks her over rougher than Bastien ever bothers. Grabs her jaw, thumbs her mouth open, slaps her tits just to watch them move. Spit lands on her cheek and nobody wipes it off. A hand closes on her throat and squeezes, not to choke, just to feel her take it and hold there.</p><p>Bruises come up under the grips. Handprints going red on her hips, on her arms, a mark on her jaw where a thumb dug in. First time it's more than one pair of hands. They pass her between them like they're testing she'll hold together.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Marks are fine. Nothing that opens the casing. She stays sealed.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Filthy machine's been handled worse than you three. Watch. She won't even flinch.</div></div><p>'Hold still, machine.'</p><p>'She don't even blink. Spit on her, watch.'</p><p>'Grab-marks come up lovely on this one.'</p>
<<set $game_state.current_canvas = "cell_use_first_three">>
<<set $game_state.current_node = "cell_use_first_three.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_first_three.n2") === -1) { vn.push("cell_use_first_three.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_first_three_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_first_three_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>They put her on her knees and open her at both ends at once. One fists her hair and feeds his cock down her throat till she gags around it, holds her there while drool ropes off her chin onto her tits; the other's behind her with his cock buried to the root in her cunt, driving her back onto the first with every thrust so she can't pull off either. She's a length of holes stretched between two men and worked from both directions.</p><p>Every stroke into her charges the core. The readout under her sternum ticks up with it. It does not tick back down. Bastien watches from the chair, writes one line, watches again.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> She was built to be used at both ends, weren't you. Filthy fucking thing.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Charge is climbing on penetration alone — note that. Nobody's even made her come yet.</div></div><p>'Look at her take it both ends.'</p><p>'Push her. There, all the way down, that's a good hole.'</p>
<<set $game_state.current_canvas = "cell_use_first_three">>
<<set $game_state.current_node = "cell_use_first_three.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_first_three.n3") === -1) { vn.push("cell_use_first_three.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_first_three_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_first_three_dp_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The third takes his turn early. They stack her. One under her with his cock in her cunt, one still fucking her throat, and the third lines up behind and shoves into her ass. The stripped socket sits empty at the base of her spine, right above where he's splitting her open. The ass used to be the drain. The part that TOOK something out of a man. Now it only fills her, the whole thing running backwards, and every cock in her stacks the charge higher.</p><p>Then one reaches under and works her clit while she's plugged at all three, forces the orgasm up out of her whether she'd give it or not. That's when the plate jumps. A come wrung out of her spikes it worse than any thrust. At this load it isn't pleasure landing anymore; it's charge with nowhere to go, the overflow gone hot and wrong under her sternum, and it climbs and climbs.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There it is. Every hole loaded and the number won't stop.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Make her come. That's the one. Forced spikes it hardest. Confirmed.</div></div><p>'All three holes. She's fuckin' full.'</p><p>'Feel that? Something's buzzing inside her.'</p><p>'Machine's overheating. Don't stop, wring it out of her.'</p>
<<set $game_state.current_canvas = "cell_use_first_three">>
<<set $game_state.current_node = "cell_use_first_three.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_first_three.n4") === -1) { vn.push("cell_use_first_three.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_first_three_Node_n5">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_first_three_they_finish_on_in_her_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>They finish where they like. One pulls out of her throat and empties across her face. Cum in her lashes, on her lips, dripping off her chin. One comes deep in her cunt and one across her back, ropes of it laid over the handprints they left there. They wipe their cocks clean on her tits and her hair when they're done with her.</p><p>She kneels there striped and dripping, and stays still. Bastien counts the loads off the plate. Every one of them registered, every one banked, none of it going anywhere.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Look at the state of you. Passed round and filled up like the thing you are.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Every load logged on the plate. She banks all of it. Nothing drains.</div></div><p>'Open your mouth, machine. There, hold it.'</p><p>'All over her back, look at that.'</p><p>'Leave it on her. Let him see what he paid for.'</p>
<<set $game_state.current_canvas = "cell_use_first_three">>
<<set $game_state.current_node = "cell_use_first_three.n5">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_first_three.n5") === -1) { vn.push("cell_use_first_three.n5"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_first_three_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>When they've filed out he crosses the cell, crouches in front of her, and wipes a smear of cum off the plate under her sternum with his thumb to read it clean. The readout has climbed hard. Further in one session than in a week of just him alone. He doesn't look at her face. He looks at the number, writes it down, and underlines it.</p><p>The strain's up with it. The charge stacks behind the plate with nowhere to go, hotter each load, and the meter only ever runs one direction.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Three at once and forced to come — fastest climb yet. Good.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Charge has nowhere to go and it's stacking. Note the strain.</div></div>
<<set $game_state.current_canvas = "cell_use_first_three">>
<<set $game_state.current_node = "cell_use_first_three.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_first_three.readout") === -1) { vn.push("cell_use_first_three.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -12.0, true, null);setup.showEffectNotification();<</script>>
[[Stay on the floor.->Location_captive_room]]<p>The notebook comes in before he does. A cheap spiral thing he sets on the crate, squares up with the edge, uncaps a pen. Then he drags the chair round to face her and sits, not close, the way a man settles in to watch a gauge rather than fuck a woman. 'Not fucking you today,' he says, almost bored. He taps his own sternum, where hers carries the plate. 'Today I want to see the needle move. You come, that thing counts it. So we're going to find out how many I can get out of you before it complains.'</p><p>He leans in and reads the readout under her sternum through the strip of grime, and he writes that number down before he's laid a hand on her. A baseline, neat, underlined twice. Cold about it. Curious. 'Filthy little machine,' he says, unhurried, more to the page than to her. 'Let's see what you do.'</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Not fucking you today. Today I want to see the needle move.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> You come, that thing counts it. We're going to find out how many I can get out of you before it complains.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Filthy little machine. Let's see what you do.</div></div>
<<set $game_state.current_canvas = "cell_use_charge_test">>
<<set $game_state.current_node = "cell_use_charge_test.base">>
<<script>>setup.markCanvasTriggered("cell_use_charge_test");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_charge_test.base") === -1) { vn.push("cell_use_charge_test.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_charge_test_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_charge_test_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He works two fingers into her cunt briskly and starts. Not for her, never for her, his eyes stay up on the plate the whole time. Slow, patient, the heel of his hand grinding a circle while his thumb finds the spot and stays on it. He isn't trying to please her. He's trying to trip a switch. 'There it is,' he murmurs, feeling her clench around him, and he doesn't sound pleased so much as confirmed. 'Wet already. Built to. You can strip everything out of a thing and it still slicks up on command like a good little hole.'</p><p>When the fingers stall he puts his mouth on her too. Tongue flat and mean and efficient, spit and friction, throttling her up the way you'd rev an engine. The whole time one eye stays on the readout under her sternum, waiting for the twitch. 'That's it. Right up to it.' He pulls back a fraction and keeps her hanging there, deliberate. 'I want the number, not you. Don't matter what you want.'</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There it is. Wet already. Built to. You can strip everything out of a thing and it still slicks up on command like a good little hole.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> That's it. Right up to it.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> I want the number, not you. Don't matter what you want.</div></div>
<<set $game_state.current_canvas = "cell_use_charge_test">>
<<set $game_state.current_node = "cell_use_charge_test.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_charge_test.n2") === -1) { vn.push("cell_use_charge_test.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_charge_test_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_charge_test_she_comes_degraded_for_it_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>It goes off without her say-so. Her cunt clamps down on his fingers and she comes, hard, hips jerking up into a hand that owns her, a sound tearing out of her that isn't a choice. He doesn't ease off through it; he holds her on the edge and wrings it out, watching her body betray her from the inside. 'There she is,' he breathes. 'Look at you. Filthy little machine, creaming all over my hand, gagging for it. Didn't even ask you nice.'</p><p>Under her sternum the readout jumps. Not a crawl, a jump, the forced one spiking it the way the slow ones never do. The charge it books has nowhere to go: the socket at the base of her spine sits empty where the drain used to seat, so it just stacks, hot, behind the plate. He watches the number leap and grins and writes it down. Not her face. The number. He wipes his fingers off on her thigh and reads the new digits out loud like a score.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There she is. Look at you. Filthy little machine, creaming all over my hand, gagging for it. Didn't even ask you nice.</div></div>
<<set $game_state.current_canvas = "cell_use_charge_test">>
<<set $game_state.current_node = "cell_use_charge_test.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_charge_test.n3") === -1) { vn.push("cell_use_charge_test.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_charge_test_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_charge_test_again_overstim_slaps_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He goes straight back down on her before the first has finished ringing out, and this time it's too much and that's the point. Fingers hard on a clit still fizzing, no mercy in it, dragging her up the raw wall of it while she's still shaking. When she flinches away he slaps her for it, open-handed, across the cunt. A wet crack. Then again across the inside of her thigh, watching the red bloom up under his palm. 'Hold still. You'll move the number or you'll wear my hand, machine. Pick one.'</p><p>The second one hurts coming out. The overflow's got nowhere to sit and it turns the pleasure to a hot ache behind her ribs. He forces it anyway, that's the whole trick, the forced ones move it fastest. She comes with a bruise already coming up on her thigh and a handprint on her cunt, jerking against a grip that holds, and the readout climbs again. He checks the plate before he checks anything else. 'Good. Again.'</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Hold still. You'll move the number or you'll wear my hand, machine. Pick one.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Good. Again.</div></div>
<<set $game_state.current_canvas = "cell_use_charge_test">>
<<set $game_state.current_node = "cell_use_charge_test.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_charge_test.n4") === -1) { vn.push("cell_use_charge_test.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_charge_test_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_charge_test_again_read_out_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He sits back on his heels, flexes his slick hand, and writes the new figure under the last. A little column building down the page now, each line higher than the one above it. He tips the plate toward the light with two fingers under her chin, not to see her, to read her, comparing the digits against the number he set down at the start. Then he turns the page. 'Climbed,' he says, satisfied, tapping the pen. 'You went up three just now. Nice steep little curve you've got.'</p><p>It doesn't drop back. That's the thing he's writing down and she isn't saying: the readout ticks up and it stays up, every one he forces out of her stacked behind the sternum plate with the socket at her spine sitting empty and useless to bleed any of it off. He caps the pen, uncaps it again, gets comfortable on the crate. 'We've got all the time in the world,' he says, and puts his hand back between her legs. 'Again.'</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Climbed. You went up three just now. Nice steep little curve you've got.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> We've got all the time in the world. Again.</div></div>
<<set $game_state.current_canvas = "cell_use_charge_test">>
<<set $game_state.current_node = "cell_use_charge_test.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_charge_test.readout") === -1) { vn.push("cell_use_charge_test.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -10.0, true, null);setup.showEffectNotification();<</script>>
[[Let him finish writing.->Location_captive_room]]<video src="./videos/scenes/cell_inventory_the_order_t4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>The door lets him in and no one else. He has a folding chair under one arm; he snaps it open a body-length from her and drops into it like a man come to look over stock he already owns. No hurry in him. He sits with his knees apart and looks her up and down the way you'd look at a crate you paid too much for and mean to get your money's worth out of, and lets the quiet sit until it's clear the quiet is his too.</p><p>She stands where the room keeps her. He takes his time getting to the point, because taking his time is part of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Take it off. All of it. Let's see what I paid for.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Slow. I've got a whole drawer of notes on you upstairs and not one of them tells me what a thing like you is worth. So I'll price you myself.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.base">>
<<script>>setup.markCanvasTriggered("cell_use_inventory");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.base") === -1) { vn.push("cell_use_inventory.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_inventory_Node_n2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_inventory_strip_on_command_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Her hands go to the collar a second late. A beat too long deciding whether to obey. That's the whole of the excuse he wants. He comes up out of the chair and he's on her before the pause is done, gets a fist in the cloth at her shoulder and tears it down off her in one hard pull, seam giving with a rip, already grabbing the next piece before the first has hit the floor. He strips her the way you'd tear the wrap off stock you paid too much for and can't be bothered to unpick. Rough, fast, cloth going in his hands. Then she's bare, the torn scraps around her feet.</p><p>He doesn't do it because he has to. He does it because making her do it herself is slower, and because tearing it off her tells her what she is here quicker than any order could. A thing to be unwrapped, not a thing to be asked. When she's bare he steps back to the chair, cock already out, and looks her over like he's checking he got what he paid for.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Too slow. When I say off, it comes off. I'll not ask a machine twice.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There. Bought and paid for, and not even worth the wrapping. Let's see what's under it.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.n2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.n2") === -1) { vn.push("cell_use_inventory.n2"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_inventory_Node_n3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_inventory_the_inspection_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He gets up only when she's bare. He checks her over like stock. Turns her by the hip, spreads her open with both thumbs, works two fingers up into her cunt and a third into her ass in the same breath, no interest at all in whether she's ready for any of it.</p><p>She keeps her mouth shut, so he spits in her face, unhurried, right across the cheek, and wipes his wet hand off on her tits. Then his thumb finds the empty socket at the base of her spine, and he stops, and works the tip of it into the hole, and laughs.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Nice and tight for a thing that's been passed round half the docks. They tell me you were a fixture in a whorehouse. Doesn't feel used up. Yet.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There it is. That's where the party trick lived. Empty as a robbed till. Somebody's had it out of you. So now you're just holes and a bill.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.n3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.n3") === -1) { vn.push("cell_use_inventory.n3"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_inventory_Node_n4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_inventory_he_fucks_her_throat_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He doesn't ask her to suck it. He fists a handful of her hair, drags her down onto his cock, and fucks it straight down her throat. Holds her there past the gag, past the point her eyes run and drool ropes off her chin onto her tits, then hauls her up for one wet breath and shoves her back down onto it.</p><p>He uses her face like it owes him money, both hands in her hair now, driving her throat down the length of him at his own pace and holding her there each time until her whole body kicks. She takes all of it, because taking it is the only thing left that she does.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There's a good hole.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> That's it. Choke on it. That part of you still works, at least.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.n4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.n4") === -1) { vn.push("cell_use_inventory.n4"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_inventory_Node_n5">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_inventory_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He pulls her up off his cock, turns her, and folds her over the table with one hand flat between her shoulder blades, holding her down against nothing because she isn't fighting. Then he pushes into her cunt and fucks her the way a man saws a board he means to use. Unhurried, all the way through, hand pressing her cheek to the wood.</p><p>When he spends himself in her he does it in silence. The charge comes off him and goes into her and stops. It climbs up behind the plate under her sternum and stacks there against the wall of the stripped socket, turning over, looking for the way out, and not finding one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> That's one in the tank. Now let's see if any of it goes anywhere.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.n5">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.n5") === -1) { vn.push("cell_use_inventory.n5"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_inventory_Node_n6">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_inventory_he_takes_her_ass_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He pulls out of her cunt still hard, works the head against her ass, and pushes in slow. It takes him longer here, and it's tighter, and he takes his time about it. He holds her by the hips and drives up into her ass an inch from the empty socket at the base of her spine. The hole that used to be the drain, the thing that TOOK, that reached down a man's spine and pulled something loose.</p><p>Now it only fills her. Every stroke stacks the charge higher with nowhere for it to run, and when he empties himself into her ass she gets all of it and there is nothing on the far end of the take. No man gone soft and honest and hers. Just his cum in her and the meter behind her sternum jumping.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> That used to be the good one, didn't it. The one that emptied a man out and left him yours. Look at it now. Just another hole I get to use.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.n6">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.n6") === -1) { vn.push("cell_use_inventory.n6"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_cell_use_inventory_Node_readout">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><video src="./videos/sex/cell_inventory_he_finishes_the_read_out_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He stays buried in her ass a beat after he finishes, breathing, then pulls out and lets it run. He wipes his cock off on the curve of her ass and steps back to look at her. Bent over his table, cheek on the wood, holding what he put in her.</p><p>The readout on the plate under her sternum ticks up one, and does not tick back down. It never ticks back down now. He watches the number, not her; takes the notebook out of his coat, and writes it in the column beside the others.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There. Up, and holding. Whatever's meant to bleed that off isn't working. Because I've got the part that does it sitting in a drawer upstairs. You just fill.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Good. We'll run it again once you've settled.</div></div>
<<set $game_state.current_canvas = "cell_use_inventory">>
<<set $game_state.current_node = "cell_use_inventory.readout">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_use_inventory.readout") === -1) { vn.push("cell_use_inventory.readout"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.applyAndNotifyTrait("player", null, "energy", "add", -10.0, true, null);setup.showEffectNotification();<</script>>
[[Get up off the table.->Location_captive_room]]<p>She comes up out of it slowly. That is new. There is a ceiling, painted a long time ago, and a light in a cage that burns all night. A bed bolted to the floor. A chair that isn't. A table with nothing on it. In the middle of the floor there is a drain, because whoever built this room expected to hose it out.</p><p>She reaches back and finds the seam at the base of her spine open and empty. It doesn't hurt. That's the part she keeps checking. It doesn't hurt, the way a missing tooth doesn't hurt, and her hand goes back to it three times before she makes it stop.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Charge comes in. Charge has to go somewhere.</div></div><p>There is a door. It is steel and newer than the room, and it has no handle on this side. She sits on the edge of the bed with her hands in her lap and listens to men moving on the other side of it, and she works out, without any particular feeling about it, that she can lie down or she can pay attention, and that those are the two things there are.</p>
<<set $game_state.current_canvas = "captivity_intro">>
<<set $game_state.current_node = "captivity_intro.base">>
<<script>>setup.markCanvasTriggered("captivity_intro");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("captivity_intro.base") === -1) { vn.push("captivity_intro.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Sit up.->Location_captive_room]]<img src="./videos/scenes/captivity_taken.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>It's the newspaper she notices, half a street back. Folded the same way, held by the same patient man who stepped aside to let them carry her past. He doesn't hurry. He doesn't need to. The van is already at the kerb behind her and the dock is long and there is nowhere on it to go that isn't further out.</p><p>This time nobody bothers with the bag until she's inside. A hand finds the seam at the base of her spine and works it, patient, the way a man works a jar lid, until it gives. The weight of the drain comes off her. Somebody says something about the boss wanting a proper look this time, and somebody else laughs, and then the bag.</p>
<<set $game_state.current_canvas = "captivity_recovery">>
<<set $game_state.current_node = "captivity_recovery.base">>
<<script>>setup.markCanvasTriggered("captivity_recovery");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("captivity_recovery.base") === -1) { vn.push("captivity_recovery.base"); }<</script>>
<<nobr>>
<<link "Go under." "Location_captive_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She doesn't hear the door. One second she's got the ledger under her arm and the stair in front of her; the next there's a bag over her head, a knee in her back, and hands that know exactly how much pressure a body takes before it stops fighting. Nobody says a word. Professionals. The last thing she registers before the dark is a man at the foot of the stair folding his newspaper, the same patient watcher from The House, stepping aside to let them carry her past.</p><p>She comes to upright in a chair that isn't restraining her. That is its own kind of message. A back room, warm light, a door that's shut and not locked. Across a plain table a man watches her with the patience of someone who owns the building and everything in it. Unhurried, certain, a voice that will never have to be raised because the room is already his.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Wren. That's the file Mercer keeps you under, so it's the one I'll use. You've been busy. Doss. Rourke. My man Marsh, who woke up Monday poorer and stupider and can't tell me why. A great deal of digging, for one of Mercer's assets — into people who are mine.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Don't reach for whatever cover you had ready. I knew you were Mercer's before you finished your first drink down here; I hear things before they're said. That isn't what interests me.</div></div><p>He leans in, unhurried, and doesn't threaten her. His hands stay where they are. He looks at her the way you'd look at the first genuinely interesting thing to cross your desk in years.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> What interests me is that when my man watched you leave The House, he swore the girl who walked out wasn't quite a girl. And my people are very rarely wrong about the things that unsettle them. So before I decide what you're worth — to me, and to the people I answer to, who'd pay a great deal for the honest answer — I'll ask you plainly. What are you, really?</div></div><p>The question hangs. She has covers for men who want her body and men who want her obedience, and none at all for a man who wants the one thing under the chip she can't reach herself. Somewhere below the amputation, something turns over at being seen. She doesn't answer. He reads the not-answering, nods as though it told him plenty, and lifts two fingers. The bag comes down again.</p><p>Hands under her arms. A stair, and then further down than a stair should go. The salt smell of the docks thins out and stops. Somewhere in the dark someone finds the seam at the base of her spine, working it the way a man works a jar lid, patient, until it gives. The weight of the drain comes off her for good. She goes under before she can count the turns.</p>
<<set $game_state.current_canvas = "hunt_the_grab">>
<<set $game_state.current_node = "hunt_the_grab.base">>
<<script>>setup.markCanvasTriggered("hunt_the_grab");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_the_grab.base") === -1) { vn.push("hunt_the_grab.base"); }<</script>>
<<nobr>>
<<link "Go under." "Location_captive_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_revealed", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "captivity_entered", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><img src="./videos/scenes/crew_den_interior.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The key's under the third stair, like Marsh said. Inside, the rooms have the stillness of a place people left fast and never came back to. A card game abandoned mid-hand, a coat that fits no one now, a fridge that gave out weeks ago and was never opened since. Doss and Rourke lived here, and died somewhere else. She takes the place apart the way she takes everything apart: cold, thorough, patient.</p>
<<set $game_state.current_canvas = "hunt_crew_den_search">>
<<set $game_state.current_node = "hunt_crew_den_search.base">>
<<script>>setup.markCanvasTriggered("hunt_crew_den_search");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_crew_den_search.base") === -1) { vn.push("hunt_crew_den_search.base"); }<</script>>
<<nobr>>
<<link "Take the place apart." "Canvas_hunt_crew_den_search_Node_find">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Not yet." "Location_underworld_strip">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It's in a strongbox behind the water heater. The one thing in the place worth locking. A run of ledgers, tallies of cargo that never touched a legal dock, and a name at the top of every page: the man the crew answered to, whose coin moved through Doss's hands and out into the company's blind spots. Not Cain. Someone she's never heard of. Bastien.</p><p>She has it now. A person at the end of the trail, a place to put the hunt. She pockets the ledger and turns for the stair.</p>
<<set $game_state.current_canvas = "hunt_crew_den_search">>
<<set $game_state.current_node = "hunt_crew_den_search.find">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_crew_den_search.find") === -1) { vn.push("hunt_crew_den_search.find"); }<</script>>
<<nobr>>
<<link "Bastien. Take the ledger and go." "Canvas_hunt_the_grab_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bastien_found", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><img src="./videos/scenes/marsh_booking.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Marsh comes in on the hour, exact. A small neat man who checks the room's exits before he checks the girl, and takes the one the madam pointed him to in silence. Her, tonight, in Rue's place. He misses the swap, or lets it go; he wants the hour he paid for. Whatever a careful man keeps behind his face, she'll have to work him loose for it. She knows the one act that opens him.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_false"}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})>>
<p>The drain sits cold against her hip. Spent on Renner, never recharged. She can take Marsh's hour for the coin, but the truth stays locked behind his face until the weapon's live. Recharge it at the cradle and take his next Sunday.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_false"}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<p>She's carrying the emitter, not the drain. Wrong weapon for this work. She can take Marsh's hour for the coin, but she'll get nothing out of him. Swap to the drain at her bench and take his next Sunday.</p>
<</if>>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.base">>
<<script>>setup.markCanvasTriggered("hunt_marsh_sunday");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.base") === -1) { vn.push("hunt_marsh_sunday.base"); }<</script>>
<<nobr>>
<<link "Take him — earn the hour." "Canvas_hunt_marsh_sunday_Node_oral">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Not tonight." "Location_underworld_strip">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_oral_t5"] to ($game_state.media_cycle["sex_marsh_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_oral_t5/c7caf640af8.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_oral_t5/c41b3d37d25.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_oral_t5/c83d39c7bfe.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_oral_t5/ccd4b0e594c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees, she takes him in her mouth and works him the way the trade taught her, but slower, watching. Reading where the careful in him loosens and where it doesn't. He rests a hand in her hair, polite even here, and lets his head go back. Getting there.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.oral">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.oral") === -1) { vn.push("hunt_marsh_sunday.oral"); }<</script>>
<<nobr>>
<<link "Keep working him." "Canvas_hunt_marsh_sunday_Node_oral">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Climb on and ride him." "Canvas_hunt_marsh_sunday_Node_vaginal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn around — give him your ass." "Canvas_hunt_marsh_sunday_Node_anal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('hunt_marsh_sunday:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_hunt_marsh_sunday_Node_finish_soft">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hunt_marsh_sunday:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_ride_t5"] to ($game_state.media_cycle["sex_marsh_ride_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_ride_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_ride_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_ride_t5/c4f9cda0ca4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_ride_t5/c79f7199221.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_ride_t5/c996d676d6d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_ride_t5/cb9bc227b81.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She climbs on and rides him slow, keeping the pace hers, watching the careful man forget to be careful. He grips her hips and lets go of something. Not much, but she's not after much. She's after the one thing men give up when she takes them the last way.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.vaginal">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.vaginal") === -1) { vn.push("hunt_marsh_sunday.vaginal"); }<</script>>
<<nobr>>
<<link "Keep riding him." "Canvas_hunt_marsh_sunday_Node_vaginal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_hunt_marsh_sunday_Node_oral">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn around — give him your ass." "Canvas_hunt_marsh_sunday_Node_anal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('hunt_marsh_sunday:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_hunt_marsh_sunday_Node_finish_soft">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hunt_marsh_sunday:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_anal_t5"] to ($game_state.media_cycle["sex_marsh_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_anal_t5/c04e940ad74.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_anal_t5/c64b03ce705.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_anal_t5/c942c12efcf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_anal_t5/cb0ac824f33.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She turns and gives him her ass, and he takes it the way careful men take the thing they'd never ask for out loud. Slow, greedy, undone by it. This is the act that opens him. Bent over the bed with his hands clamped on her hips, she waits for the moment his whole guarded weight goes soft, and reaches, if she's carrying it, for the drain.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.anal">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.anal") === -1) { vn.push("hunt_marsh_sunday.anal"); }<</script>>
<<nobr>>
<<link "Take it — work him to the edge." "Canvas_hunt_marsh_sunday_Node_anal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back onto his cock." "Canvas_hunt_marsh_sunday_Node_vaginal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_false"}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('hunt_marsh_sunday:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — take the drain." "Canvas_hunt_marsh_sunday_Node_drain">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hunt_marsh_sunday:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('hunt_marsh_sunday:cc3') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass." "Canvas_hunt_marsh_sunday_Node_finish_ass_paid">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hunt_marsh_sunday:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_false"}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('hunt_marsh_sunday:cc4') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — the drain's spent." "Canvas_hunt_marsh_sunday_Node_finish_ass_nodrain">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hunt_marsh_sunday:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "crew_known", "operator": "is_false"}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('hunt_marsh_sunday:cc5') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass — you're carrying the wrong gear." "Canvas_hunt_marsh_sunday_Node_finish_ass_nodrain">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hunt_marsh_sunday:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><video src="./videos/sex/marsh_finish_ass_drain_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>He finishes in her ass, and the drain wakes with him. The same act that hands her nothing with a paying man hands her everything with this one. The careful goes out of him all at once, loose and honest, his guarded weight gone soft against her back. She asks the only thing she came for: where the crew lived. Doss, Rourke, the rest. He tells her. A dead man's rooms down past the market, nobody's cleared them, the door still answers to a key under the third stair. In a few minutes he'll surface remembering a good hour and nothing else.</p><p>On her way out a man at the bar folds his paper and watches her go. Not the madam's muscle, someone else's, patient about it. She clocks him clocking her and files it. Careful men keep careful company; someone just paid attention to the wrong girl asking the wrong questions.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.drain">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.drain") === -1) { vn.push("hunt_marsh_sunday.drain"); }<</script>>
<<nobr>>
<<link "Take the address and go." "Location_underworld_strip">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "crew_known", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_finish_facial_t5"] to ($game_state.media_cycle["sex_marsh_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_finish_facial_t5/c4fafc11b46.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_finish_facial_t5/c4ff543aef2.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_finish_facial_t5/c869acbdd6b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_finish_facial_t5/cb727dd478d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_finish_inside_t5"] to ($game_state.media_cycle["sex_marsh_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_finish_inside_t5/c12d725a7ca.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_finish_inside_t5/c52f3226be0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_finish_inside_t5/ca7f453e47e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_finish_inside_t5/ce583676f24.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<</if>><p>He finishes the way he came in. Quiet, contained, already reaching for his coat before his breath's back. A careful man keeps his softness behind him when he doesn't lose the last of himself, and the mouth and the cunt don't cost him that. She takes the coin he leaves and lets him go. Whatever he knows is still behind his face. It's the ass that opens him. She'll need him again, and the drain worn and charged.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.finish_soft">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.finish_soft") === -1) { vn.push("hunt_marsh_sunday.finish_soft"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
[[Clean up. Collect.->Location_underworld_brothel]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_finish_ass_paid_t5"] to ($game_state.media_cycle["sex_marsh_finish_ass_paid_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_finish_ass_paid_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_finish_ass_paid_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_finish_ass_paid_t5/c1822635c2a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_finish_ass_paid_t5/c3681576600.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_finish_ass_paid_t5/cc44fa20b5f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_finish_ass_paid_t5/cd52b8a5539.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes in her ass and goes slack against her, spent and honest and empty of anything she still needs. She took what was behind his face already, and a man only has the one secret worth the drain. Now he's just a careful regular with a standing Sunday, tipping fair, none the wiser. She straightens, takes the coin, and lets him go.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.finish_ass_paid">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.finish_ass_paid") === -1) { vn.push("hunt_marsh_sunday.finish_ass_paid"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
[[Clean up. Collect.->Location_underworld_brothel]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_marsh_finish_ass_nodrain_t5"] to ($game_state.media_cycle["sex_marsh_finish_ass_nodrain_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_marsh_finish_ass_nodrain_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_marsh_finish_ass_nodrain_t5"]>><<if _mc is 0>><video src="./videos/sex/marsh_finish_ass_nodrain_t5/c1c8eee83cb.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/marsh_finish_ass_nodrain_t5/c17da28b611.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/marsh_finish_ass_nodrain_t5/cd93aba33bf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/marsh_finish_ass_nodrain_t5/ce8bc87ef43.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He finishes in her ass and the careful goes out of him. Loose, open, everything he knows a touch away. She's got nothing on her to take it with. Without the drain worn and charged he's just a spent john with a soft face and a secret still locked behind it. She takes his coin and files the miss. Recharge the drain at the cradle, carry it, take his Sunday again. The truth's a touch away once the weapon's on her.</p>
<<set $game_state.current_canvas = "hunt_marsh_sunday">>
<<set $game_state.current_node = "hunt_marsh_sunday.finish_ass_nodrain">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_sunday.finish_ass_nodrain") === -1) { vn.push("hunt_marsh_sunday.finish_ass_nodrain"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
[[Clean up. Collect.->Location_underworld_brothel]]<p>Sunday, and the House keeps its one clock. Rue's at her chair with the ledger open to tonight's page, the far room already blocked out in her own hand. A few hours yet before the careful little man walks in expecting her.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Your Sunday standing. The careful little man, same hour every week. I want tonight.</div></div><p>A slow look up from the ledger, reassessing. She knows exactly who the girl means, and lets the why alone.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> Marsh. Quiet money, tips fair, never any trouble. The kind of regular you don't hand off. But I could use a night that's mine, and you've got the look of someone who wants him for more than the coin.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> So take tonight. Tonight, mind. Not my Sundays. He's on the hour, the far room. Whatever your business is, keep it off my floor, and he never hears from me that the girl got swapped. You want him again, you come ask me again.</div></div>
<<set $game_state.current_canvas = "hunt_marsh_scheme">>
<<set $game_state.current_node = "hunt_marsh_scheme.base">>
<<script>>setup.markCanvasTriggered("hunt_marsh_scheme");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hunt_marsh_scheme.base") === -1) { vn.push("hunt_marsh_scheme.base"); }<</script>>
<<nobr>>
<<link "Tonight, then. The far room." "Location_underworld_brothel">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "rue_met", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Not this week." "Location_underworld_brothel">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The floor's quiet this hour. A girl asleep in a chair, a lamp left burning low, the rooms all shut. The madam runs the House by day; nothing moves through here until she's back at her post. Come back when she's in, if it's work you're after.</p>
<<set $game_state.current_canvas = "brothel_offhours">>
<<set $game_state.current_node = "brothel_offhours.base">>
<<script>>setup.markCanvasTriggered("brothel_offhours");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("brothel_offhours.base") === -1) { vn.push("brothel_offhours.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Head back up.->Location_underworld_strip]]<p>Rue keeps her chair by the rooms, ledger open, watching the floor the way a dealer watches a table. She nods when she sees her. Not warmth, just the level look of one working woman clocking another.</p>
<<set $game_state.current_canvas = "rue_hub">>
<<set $game_state.current_node = "rue_hub.base">>
<<script>>setup.markCanvasTriggered("rue_hub");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rue_hub.base") === -1) { vn.push("rue_hub.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "brothel_hired", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('rue_hub:cc0') ? '' : 'unlocked-choice'">
<<link "Ask her for work." "Canvas_rue_hub_Node_work">><<script>>setup.markChoiceVisited("rue_hub:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "brothel_hired", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('rue_hub:cc1') ? '' : 'unlocked-choice'">
<<link "Trade a word." "Canvas_rue_hub_Node_talk">><<script>>setup.markChoiceVisited("rue_hub:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave her to it." "Location_underworld_brothel">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I want the work. The rooms.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> Course you do. They all do, once they've been down here long enough to stop pretending otherwise.</div></div><p>She writes something in the ledger without looking up. A name, or a mark against one. Then tips her head at the rooms. That's the whole hiring. No contract, no questions.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> Rooms are yours when you want them. Coin's yours after. Don't make me regret the chair I didn't get up from.</div></div>
<<set $game_state.current_canvas = "rue_hub">>
<<set $game_state.current_node = "rue_hub.work">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rue_hub.work") === -1) { vn.push("rue_hub.work"); }<</script>>
<<nobr>>
<<link "You won't." "Canvas_rue_hub_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "brothel_hired", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She trades what she hears, the small weather of the underworld. Which men are talking, whose protection got thinner this week, who's asking after who. "You didn't get it off me," she says every time, and tells her anyway. It isn't much. But it's a face down here that isn't a mark and isn't an owner, and there aren't many of those.</p>
<<set $game_state.current_canvas = "rue_hub">>
<<set $game_state.current_node = "rue_hub.talk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rue_hub.talk") === -1) { vn.push("rue_hub.talk"); }<</script>>
<<nobr>>
<<link "Good talking." "Location_underworld_brothel">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><img src="./videos/scenes/rue_madam.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The woman by the rooms takes her measure before she's three steps in. The flat, unhurried read of someone who's priced a thousand bodies and is rarely wrong by much. She doesn't get up.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> Rue. I run this house. Not the muscle, not the owner. The floor. Which means I decide who works my rooms and who serves the few names worth keeping. You've got the look of someone who's been used for it before and stopped feeling it. Down here that's not a mark against you. That's the job.</div></div><p>She tips her head at the rooms behind her. The offer plain, no contract, no company, nobody signing the girl out at the end of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/rue.jpg" alt="Rue" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Rue</strong> Coin's yours when you're done, and nobody up top hears a word of it from me. You want in, you ask me. Simple as that.</div></div>
<<set $game_state.current_canvas = "rue_intro">>
<<set $game_state.current_node = "rue_intro.base">>
<<script>>setup.markCanvasTriggered("rue_intro");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rue_intro.base") === -1) { vn.push("rue_intro.base"); }<</script>>
<<nobr>>
<<link "Take her measure back." "Location_underworld_brothel">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "rue_introduced", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She slides onto the stool beside him and it's wrong before she's said a word. Out of the coveralls, in her own clean clothes, she's not the dock-rat who hauls his crates. She's a stranger sitting too close, and his bleary eyes narrow on her with the old wariness coming up through the drink.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> ...do I know you? You don't look like you tonight.</div></div><p>Even three drinks down he knows the shape of her is off. Nothing she wants from him happens while she's wearing the wrong face. The cover's back in her quarters, where it does her no good.</p>
<<set $game_state.current_canvas = "react_renner_nocover_anchor">>
<<set $game_state.current_node = "react_renner_nocover_anchor.base">>
<<script>>setup.markCanvasTriggered("react_renner_nocover_anchor");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_renner_nocover_anchor.base") === -1) { vn.push("react_renner_nocover_anchor.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave before he sobers on it.->Location_the_anchor]]<p>She comes onto the floor and Renner's head comes up wrong. She's in her own clothes, the clean expensive line of them all out of place against the racks. No coveralls. For a second he doesn't place her at all. Then the wariness: not recognition. Suspicion.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> ...the hell are you dressed like that for. Do I know you?</div></div><p>Wrong skin for this yard. Whatever she'd get done here today, this is the wrong face for it. The cover's back in her quarters, useless on the rack.</p>
<<set $game_state.current_canvas = "react_renner_nocover_depot">>
<<set $game_state.current_node = "react_renner_nocover_depot.base">>
<<script>>setup.markCanvasTriggered("react_renner_nocover_depot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_renner_nocover_depot.base") === -1) { vn.push("react_renner_nocover_depot.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Get out before he looks harder.->Location_renner_depot]]<img src="./videos/scenes/renner_anchor.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Renner's at the end of the bar. She takes the stool and starts in. Heard he's rebuilding, looking for work. She watches it land wrong. She's too clean. Too put-together for a woman who'd want a dock-rat's wages. He looks at her the way a man with enemies looks at a stranger who knows his business.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Whatever you are — cop, fed, one of theirs — I've got nothing to say to it. Off my stool.</div></div><p>He turns his shoulder and that's the end of it. Dressed like this she's not cheap hands; she's a question, and a man this far down walks away from questions. She'd have to come at him as something the eye slides off. The cover's in her quarters, and it does her no good on the rack.</p>
<<set $game_state.current_canvas = "react_renner_threat">>
<<set $game_state.current_node = "react_renner_threat.base">>
<<script>>setup.markCanvasTriggered("react_renner_threat");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("react_renner_threat.base") === -1) { vn.push("react_renner_threat.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave it.->Location_the_anchor]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_anal_once", "operator": "is_true"}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_cheerup_alley_t5"] to ($game_state.media_cycle["sex_renner_cheerup_alley_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_cheerup_alley_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_cheerup_alley_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_cheerup_alley_t5/c2f12625060.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_cheerup_alley_t5/c007f3a0a9e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_cheerup_alley_t5/c8a9b68c694.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_cheerup_alley_t5/ced2d137d68.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He's wrecked tonight, and she does the thing that works. She gets him out of the bar and into the dark behind it and gives him whatever he needs. On her knees on the filthy concrete, or bent over a crate, the cold boss falling apart and the help putting him back together with her mouth and her ass. It's the one real thing she has, and she spends it on him like it's nothing, because it is.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_oral_once", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "renner_anal_once", "operator": "is_false"}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_cheerup_oral_t5"] to ($game_state.media_cycle["sex_renner_cheerup_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_cheerup_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_cheerup_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_cheerup_oral_t5/c3f7a9fddc5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_cheerup_oral_t5/c5e34c5d737.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_cheerup_oral_t5/c8c8352e5f1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_cheerup_oral_t5/c0521ec1329.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>He's low tonight. She slips off the stool and into the dark beside the cigarette machine and takes his cock in her mouth right there, fast and devoted, the bartender pointedly not looking. He comes with his hand in her hair saying her work-name like a man saying his prayers wrong.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_oral_once", "operator": "is_false"}]})>>
<p>He's low tonight. Too low to do anything but sit in it. She sits closer than she needs to, lets her thigh press his, lets her hand rest high on his leg where the wanting has somewhere to go. It's not much. But it makes the worst of the night about her instead of about the wreck of his life, and that's the seed of everything that comes after.</p>
<</if>>
<<set $game_state.current_canvas = "amb_renner_cheerup">>
<<set $game_state.current_node = "amb_renner_cheerup.base">>
<<script>>setup.markCanvasTriggered("amb_renner_cheerup");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("amb_renner_cheerup.base") === -1) { vn.push("amb_renner_cheerup.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave him steadier.->Location_the_anchor]]<img src="./videos/scenes/amb_renner_anchor_ruin.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 20}]})>>
<p>Two stools down he's telling the bartender a story about the depot before Cain. When it was something, when he was something. The bartender's heard it. So has she. Renner doesn't notice either of them stopped listening a while ago.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 20}, {"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 40}]})>>
<p>There's a letter on the bar in front of him tonight he keeps not reading. Blacklist stationery, the third this month. He drinks around it. When he catches her looking he turns it face-down, too late, and orders another.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 40}]})>>
<p>He's further gone tonight than she's seen him. Talking too much, too loud, the rot all the way to the surface. What they made him part of. What burned. What he signed for and told himself he didn't understand. He won't remember saying any of it tomorrow. She'll remember all of it. It's the guilt the seduction never has to touch.</p>
<</if>>
<<set $game_state.current_canvas = "amb_renner_anchor_ruin">>
<<set $game_state.current_node = "amb_renner_anchor_ruin.base">>
<<script>>setup.markCanvasTriggered("amb_renner_anchor_ruin");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("amb_renner_anchor_ruin.base") === -1) { vn.push("amb_renner_anchor_ruin.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Let him drink.->Location_the_anchor]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 20}]})>>
<p>She's halfway up a ladder with a crate when she feels it. Renner, stopped at the bottom, not pretending to check a manifest, just watching her work. He looks away when she looks down. But he was watching, and now they both know he was.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 20}, {"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 40}]})>>
<p>He finds reasons to be where she is. Stands too close at the racks, hands her tools she didn't ask for, lets the backs of his fingers find her arm. "You're good at this," he says, like it costs him, and stays where he is when he's said it.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 40}]})>>
<p>He doesn't bother with the pretext anymore. He takes the crate out of her hands, sets it down, and backs her into the shelving with his whole ruined weight against her. "Leave it," he says against her neck. "The invoices can wait. Come in the back."</p>
<</if>>
<<set $game_state.current_canvas = "walkin_renner_depot">>
<<set $game_state.current_node = "walkin_renner_depot.base">>
<<script>>setup.markCanvasTriggered("walkin_renner_depot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("walkin_renner_depot.base") === -1) { vn.push("walkin_renner_depot.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[...->Location_renner_depot]]<p>He'll answer anything now, and remember none of it. She crouches to his eye level and asks, quiet, the way you'd read a meter.</p><span id="cascade-b1-beat-0"><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> The gear you sold Vance. What did it build?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Containment. Restraint rigs, suppression fields, a wet lab built to hold things that aren't supposed to be holdable. I didn't ask what. They paid on time and I had a business to save.</div></div><span id="cascade-b1-beat-1"><<linkreplace "What did Cain take?">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> When Cain hit the facility. What did he take?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Nothing. He freed it. Whatever they were holding in there, he let it out before he burned the place. The manifests after didn't add up. They were short bodies that weren't bodies. He wasn't robbing them. He was emptying a cage.</div></div><p>She files it somewhere the cradle can't reach. The monster she's sent to kill broke into the worst place these people built and let the prisoners walk out. It doesn't fit the briefing. Nothing about him fits the briefing, and the not-fitting is starting to have a shape.</p><span id="cascade-b1-beat-2"><<linkreplace "Why did Cain burn you down?">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Cain didn't just walk away from you. He came for you. Why?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Two of my people. Doss and Rourke. They moved my materials. And they were moving them to him too, feeding Cain off my own floor. When I found out I didn't just cut them loose. I did them, and everyone in their houses, the same night. He burned me to the slab for it. We've been at each other since.</div></div><p>She keeps her face a meter-reader's blank. So the burned yard she's been picking through wasn't collateral in someone else's war. It was the answer, and the two files she pulled out there are the men he's confessing to now. The wreck of him has a shape after all, and the shape is a debt.</p><span id="cascade-b1-beat-3"><<linkreplace "Where is he now?">><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Where would he go to ground?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> I don't know. But those two came up out of the underworld before they ever came to me. That's where their kind runs. If Cain's anywhere, he's down there. That's all I... that's all I have.</div></div><span id="cascade-b1-beat-4"><<linkreplace "Tell him to forget.">><p>She tells him to forget, and he will. In a few minutes he'll surface blinking, his cock going soft and no memory of the last ten, certain only that the new hire is very good and he should keep her close. She fixes her clothes while the man who just handed her everything stares at nothing.</p>[[Leave him to come back to himself.->Location_renner_depot]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "renner_control_canvas">>
<<set $game_state.current_node = "renner_control_canvas.intro">>
<<script>>setup.markCanvasTriggered("renner_control_canvas");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("renner_control_canvas.intro") === -1) { vn.push("renner_control_canvas.intro"); }<</script>>
<<script>>advanceTime(3);<</script>><p>He goes soft and open the second she's done, the controls warm in her hand again. Hers for a few minutes, and he won't remember a second of it. She already has what he knew. There's nothing left in him she needs; there's only what she feels like taking.</p>
<<set $game_state.current_canvas = "renner_control_canvas">>
<<set $game_state.current_node = "renner_control_canvas.again">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("renner_control_canvas.again") === -1) { vn.push("renner_control_canvas.again"); }<</script>>
<<nobr>>
<<link "Ask him again." "Canvas_renner_control_canvas_Node_again_ask">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Just leave him." "Location_renner_depot">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She crouches to his eye level and asks anyway. The gear, the two he buried, where the man went.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Two of mine — Doss and Rourke — feeding him off my floor. I did them and theirs, and he burned me for it. Where he went — down. It's all down in the underworld. That's everything I had. I swear it.</div></div><p>The same confession, in the same order. But this time she keeps the two names. He doesn't know he's said it before, and he never will. Whatever she already had, watching the wrecked man empty himself out for her on command is its own kind of confirmation. She fixes her clothes and leaves him to surface alone.</p>
<<set $game_state.current_canvas = "renner_control_canvas">>
<<set $game_state.current_node = "renner_control_canvas.again_ask">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("renner_control_canvas.again_ask") === -1) { vn.push("renner_control_canvas.again_ask"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Leave him to come back to himself.->Location_renner_depot]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<p>He finishes on her face with a groan that's half a sob, one hand cradling the back of her head like she's something he can't believe he's allowed. He'd give her anything right now. He doesn't know yet how much that's going to cost him.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_finish_facial_t5"] to ($game_state.media_cycle["sex_renner_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_finish_facial_t5/ca6028f32a7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_finish_facial_t5/cc2ef54d54d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_finish_facial_t5/ce6f50a12d0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_finish_facial_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<p>He finishes inside her, holding her down on him, shaking. For a moment after he just breathes into her shoulder, wrecked and grateful, and she lets him have the moment because letting him have it is how she keeps him.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_finish_inside_t5"] to ($game_state.media_cycle["sex_renner_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_finish_inside_t5/c78dd1b8fc6.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_finish_inside_t5/cdfbe162355.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_finish_inside_t5/ce840505218.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_finish_inside_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<p>He finishes in her ass, and the controls slide warm into her hand. The give, the opening, his whole ruined weight gone pliant against her back. The same act that hands her nothing with Mercer hands her everything with him.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_finish_anal_t5"] to ($game_state.media_cycle["sex_renner_finish_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_finish_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_finish_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_finish_anal_t5/c293e348327.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_finish_anal_t5/ca75bdf1c40.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_finish_anal_t5/cc418bf2714.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_finish_anal_t5/cff8c06501b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<</if>>
<<set $game_state.current_canvas = "loop_renner_finisher">>
<<set $game_state.current_node = "loop_renner_finisher.climax">>
<<script>>setup.markCanvasTriggered("loop_renner_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_renner_finisher.climax") === -1) { vn.push("loop_renner_finisher.climax"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_renner_finisher:cc0') ? '' : 'unlocked-choice'">
<<link "Straighten up." "Location_renner_depot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_finisher:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "drains_done", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_renner_finisher:cc1') ? '' : 'unlocked-choice'">
<<link "Take the keys." "Canvas_renner_control_canvas_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drains_done", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_drained", "set");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_leads_extracted", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_finisher:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "drains_done", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_renner_finisher:cc2') ? '' : 'unlocked-choice'">
<<link "Take the keys." "Canvas_renner_control_canvas_Node_again">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drains_done", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "names_known", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_finisher:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('loop_renner_finisher:cc3') ? '' : 'unlocked-choice'">
<<link "Let it go — the drain's empty. Recharge it at the cradle." "Location_renner_depot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_finisher:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('loop_renner_finisher:cc4') ? '' : 'unlocked-choice'">
<<link "Let it go — the drain's empty. Take a night on the feed line at the berth and it reloads." "Location_renner_depot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_finisher:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('loop_renner_finisher:cc5') ? '' : 'unlocked-choice'">
<<link "Let it go — wrong gear." "Location_renner_depot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_finisher:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "drains_done", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "drains_done", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})))>>
<<script>>
try {
window._engineNoExitsDiag_loop_renner_finisher = [{"text": "Straighten up.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "lt", "value": 2}]}}, {"text": "Take the keys.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "drains_done", "operator": "lt", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]}}, {"text": "Take the keys.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "drains_done", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "gte", "value": 1}]}}, {"text": "Let it go \u2014 the drain's empty. Recharge it at the cradle.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]}}, {"text": "Let it go \u2014 the drain's empty. Take a night on the feed line at the berth and it reloads.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "drain_charge", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}]}}, {"text": "Let it go \u2014 wrong gear.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "loop_renner_finisher",
choices: window._engineNoExitsDiag_loop_renner_finisher,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_loop_renner_finisher>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas loop_renner_finisher</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Navigation]]
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_loop_t5"] to ($game_state.media_cycle["sex_renner_loop_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_loop_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_loop_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_loop_t5/c88bd692ed4.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_loop_t5/cbf1782f954.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_loop_t5/cdd4c416ab0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_loop_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She locks the office door. He's already reaching for her. The cold boss gone, just a wrecked man who's spent all day waiting for the help to come and take him apart.</p>
<<set $game_state.current_canvas = "loop_renner_office_sex">>
<<set $game_state.current_node = "loop_renner_office_sex.intro">>
<<script>>setup.markCanvasTriggered("loop_renner_office_sex");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_renner_office_sex.intro") === -1) { vn.push("loop_renner_office_sex.intro"); }<</script>>
<<nobr>>
<<link "Get on your knees." "Canvas_loop_renner_office_sex_Node_base_oral_r">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_loop_oral_t5"] to ($game_state.media_cycle["sex_renner_loop_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_loop_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_loop_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_loop_oral_t5/c1e6b2a4bed.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_loop_oral_t5/c377a6771c3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_loop_oral_t5/c4078dc881e.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_loop_oral_t5/ce724bed764.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees between the chair and the desk, his cock in her mouth, his hand gentler in her hair than Mercer's hand has ever been. Renner holds on like he's afraid she'll stop.</p>
<<set $game_state.current_canvas = "loop_renner_office_sex">>
<<set $game_state.current_node = "loop_renner_office_sex.base_oral_r">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_renner_office_sex.base_oral_r") === -1) { vn.push("loop_renner_office_sex.base_oral_r"); }<</script>>
<<nobr>>
<<link "Keep sucking his cock." "Canvas_loop_renner_office_sex_Node_base_oral_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Climb on his cock." "Canvas_loop_renner_office_sex_Node_base_vaginal_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_renner_office_sex:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_loop_renner_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_office_sex:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_loop_vaginal_t5"] to ($game_state.media_cycle["sex_renner_loop_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_loop_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_loop_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_loop_vaginal_t5/c7c8a68085f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_loop_vaginal_t5/c7f9cece542.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_loop_vaginal_t5/c9d59417c72.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_loop_vaginal_t5/ccfd2393d12.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She rides him in the office chair, slow, watching the last of his composure go. He says things he'll be ashamed of. Please, and the false name she works under, and don't stop, don't ever stop.</p>
<<set $game_state.current_canvas = "loop_renner_office_sex">>
<<set $game_state.current_node = "loop_renner_office_sex.base_vaginal_r">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_renner_office_sex.base_vaginal_r") === -1) { vn.push("loop_renner_office_sex.base_vaginal_r"); }<</script>>
<<nobr>>
<<link "Take him." "Canvas_loop_renner_office_sex_Node_base_vaginal_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on his cock." "Canvas_loop_renner_office_sex_Node_base_oral_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 50}, {"type": "clothing_item", "item_id": "cover_dockhand", "operator": "equipped"}]})>>
<span @class="setup.isChoiceVisited('loop_renner_office_sex:cc1') ? '' : 'unlocked-choice'">
<<link "Turn around — give him your ass." "Canvas_loop_renner_office_sex_Node_base_doggy_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_anal_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_office_sex:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Not yet — he has to be all the way broken first.">Not yet — he has to be all the way broken first.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('loop_renner_office_sex:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_loop_renner_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_office_sex:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_renner_loop_doggy_t5"] to ($game_state.media_cycle["sex_renner_loop_doggy_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_renner_loop_doggy_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_renner_loop_doggy_t5"]>><<if _mc is 0>><video src="./videos/sex/renner_loop_doggy_t5/c2d860ae082.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/renner_loop_doggy_t5/c22c386f83a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/renner_loop_doggy_t5/c157da6227a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/renner_loop_doggy_t5/cdc391571f0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Bent over his own desk, his cock in her ass, his hands shaking on her hips. This is the act that hands her the keys. Now that she's turned it on him once, she can take them again whenever she likes.</p>
<<set $game_state.current_canvas = "loop_renner_office_sex">>
<<set $game_state.current_node = "loop_renner_office_sex.base_doggy_r">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("loop_renner_office_sex.base_doggy_r") === -1) { vn.push("loop_renner_office_sex.base_doggy_r"); }<</script>>
<<nobr>>
<<link "Take it in the ass." "Canvas_loop_renner_office_sex_Node_base_doggy_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back on his cock." "Canvas_loop_renner_office_sex_Node_base_vaginal_r">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('loop_renner_office_sex:cc3') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass." "Canvas_loop_renner_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("loop_renner_office_sex:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><video src="./videos/sex/ma_renner_blowjob_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>Next afternoon, the office, like nothing happened. Except she won't let it be like nothing happened. She waits until he's mid-sentence about a shipment, then asks him level, watching his face:</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Did you like it. Yesterday. Or not.</div></div><p>He can't get out of it. She watches him try. The bluster, the deflection, the reach for the cold he used to have. She watches all of it fail, because the answer's already on him, plain. "You know I did," he says at last, like it's dragged out of him. And that's the thing she came for: not the yes, the surrender in having to say it. He's further in than he was, and he can feel it too.</p>
<<set $game_state.current_canvas = "ma_renner_blowjob">>
<<set $game_state.current_node = "ma_renner_blowjob.base">>
<<script>>setup.markCanvasTriggered("ma_renner_blowjob");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("ma_renner_blowjob.base") === -1) { vn.push("ma_renner_blowjob.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "add", 3.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "ma_blowjob_seen", "set");<</script>>
[[Leave it sitting on him.->Location_renner_depot]]<video src="./videos/sex/renner_blowjob_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>His wanting runs ahead of him all day now. She picks the afternoon. The door shut, the yard empty, his hands shaking around a pen that isn't writing anything. She crosses to him and goes down on her knees in front of the chair, and for once he drops the pretence and lets it be what it is.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> ...you don't have to.</div></div><p>It's the first kind thing he's said to her, and it's a lie, and they both let it be one. She takes his cock out and takes him in her mouth, and the cold boss makes a sound like something giving way under load.</p><span id="cascade-b2-beat-1"><<linkreplace "Work him.">><p>She works him slow, the way she's learned men like him want it. Not skilled exactly, but devoted, like he's the only thing in the room worth her mouth. He finishes with his fist in her hair and the false name she's working under coming out of him broken in half. She swallows, and clocks the shape of what just cracked in him.</p>[[Wipe your mouth, get back to work.->Location_renner_depot]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_renner_blowjob">>
<<set $game_state.current_node = "cap_renner_blowjob.base">>
<<script>>setup.markCanvasTriggered("cap_renner_blowjob");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_renner_blowjob.base") === -1) { vn.push("cap_renner_blowjob.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "renner_oral_once", "set");<</script>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_renner_grope_t4"] to ($game_state.media_cycle["scenes_rung_renner_grope_t4"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_renner_grope_t4"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_renner_grope_t4"]>><<if _mc is 0>><video src="./videos/scenes/rung_renner_grope_t4/c82aa36e4dc.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_renner_grope_t4/ca26f3feffe.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_renner_grope_t4/cf090876321.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_renner_grope_t4/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She stops pretending the contact is accidental. A hand on his thigh while he signs something, sliding up, letting him feel that she means it.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 30}]})>>
<p>He goes still. The pen stops. For a second the gutted business and the blacklist and the drinking are gone and there's just her hand and his breathing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> ...don't stop.</div></div><p>Then he catches himself and pulls back, and hates that he had to.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 30}]})>>
<p>He doesn't pretend anymore. He covers her hand with his and presses it harder against him, his head going back, the cold boss just a man in a chair letting the help take him apart.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Whatever this is. Don't — don't stop doing it.</div></div>
<</if>>
<<set $game_state.current_canvas = "rung_renner_grope">>
<<set $game_state.current_node = "rung_renner_grope.base">>
<<script>>setup.markCanvasTriggered("rung_renner_grope");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_renner_grope.base") === -1) { vn.push("rung_renner_grope.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
[[Back to the invoices.->Location_renner_depot]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_renner_flash_t3"] to ($game_state.media_cycle["scenes_rung_renner_flash_t3"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_renner_flash_t3"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_renner_flash_t3"]>><<if _mc is 0>><video src="./videos/scenes/rung_renner_flash_t3/c3e9b103be9.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_renner_flash_t3/c0814f3a987.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_renner_flash_t3/cd2f90ecdd8.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_renner_flash_t3/cee231736f1.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She's wearing nothing under the coveralls today, and she makes sure the moment comes where he can't not see it. Bending slow for a low crate while he's looking.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 20}]})>>
<p>He looks. He looks longer than a man pretending not to. Then he turns hard to the window.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Get back to work.</div></div><p>His voice has gone rough. He doesn't mean the window.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 20}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Christ. Come here.</div></div><p>He says it low, half to himself, and doesn't finish the order. He doesn't know what he'd do with her if she came. The wanting's ahead of the nerve. But it's there now, plain, and they both felt it land.</p>
<</if>>
<<set $game_state.current_canvas = "rung_renner_flash">>
<<set $game_state.current_node = "rung_renner_flash.base">>
<<script>>setup.markCanvasTriggered("rung_renner_flash");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_renner_flash.base") === -1) { vn.push("rung_renner_flash.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
[[Back to the invoices.->Location_renner_depot]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["scenes_rung_renner_tease_t2"] to ($game_state.media_cycle["scenes_rung_renner_tease_t2"] === undefined ? 0 : ($game_state.media_cycle["scenes_rung_renner_tease_t2"] + 1) % 4)>><<set _mc to $game_state.media_cycle["scenes_rung_renner_tease_t2"]>><<if _mc is 0>><video src="./videos/scenes/rung_renner_tease_t2/c8e0b66b889.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/scenes/rung_renner_tease_t2/c78be8006e3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/scenes/rung_renner_tease_t2/ce10b88bda5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/scenes/rung_renner_tease_t2/cf1e91bb982.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>In the office now, the door shut. She works close. Leans across him for a file she doesn't need, lets her body say the thing she keeps out of her mouth.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "lt", "value": 10}]})>>
<div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Filing's in the cabinet. Not on my desk.</div></div><p>He doesn't look up. But he moves his chair back an inch, and the inch costs him something.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 10}]})>>
<p>His eyes go to her and snap away, and a muscle works in his jaw.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> ...You do that on purpose.</div></div><p>It isn't quite a question, and he doesn't tell her to stop.</p>
<</if>>
<<set $game_state.current_canvas = "rung_renner_tease">>
<<set $game_state.current_node = "rung_renner_tease.base">>
<<script>>setup.markCanvasTriggered("rung_renner_tease");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("rung_renner_tease.base") === -1) { vn.push("rung_renner_tease.base"); }<</script>>
<<script>>advanceTime(180);<</script>>
[[Back to the invoices.->Location_renner_depot]]<img src="./videos/scenes/renner_office.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>It takes a week of good work before he stops finding fault just to have something to say to her. Then one grey afternoon he jerks his head at the glassed-in box at the back of the yard. His office. He doesn't quite look at her when he says it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Invoices are three months behind and I can't read my own writing. You'll do them in here. Heater works, door shuts, and I don't have to watch the help breathe.</div></div><p>It's the closest thing to trust a man this gutted has left to give. The door clicks shut behind her, and the public yard with its cameras and its cold becomes, for the length of a workday, a small private room with one wrecked man in it. Everything she's here to do starts now.</p>
<<set $game_state.current_canvas = "cap_renner_noticed">>
<<set $game_state.current_node = "cap_renner_noticed.base">>
<<script>>setup.markCanvasTriggered("cap_renner_noticed");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_renner_noticed.base") === -1) { vn.push("cap_renner_noticed.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "renner_office_open", "set");<</script>>
[[Get to work.->Location_renner_depot]]<<set _sub_target = setup.checkAndSubstituteCanvas("hub_anchor_renner")>><<if _sub_target>><<goto _sub_target>><</if>>
<img src="./videos/scenes/renner_anchor_evening.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Renner's at his end of the bar, working on the evening's ruin. Off the clock he's quieter and worse. Less temper, more rot. He tolerates her sitting near him now. That is its own kind of progress.</p>
<<set $game_state.current_canvas = "hub_anchor_renner">>
<<set $game_state.current_node = "hub_anchor_renner.base">>
<<script>>setup.markCanvasTriggered("hub_anchor_renner");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_anchor_renner.base") === -1) { vn.push("hub_anchor_renner.base"); }<</script>>
<<nobr>>
<<link "Sit with him a while." "Canvas_hub_anchor_renner_Node_sit">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Leave." "Location_the_waterfront">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She sits. He drinks. She stays. The bartender refills him unasked. Somewhere in the quiet she clocks what she sees. The blacklist letters he doesn't hide anymore, the way his hands shake until the second drink. She lets him think it's company.</p>
<<set $game_state.current_canvas = "hub_anchor_renner">>
<<set $game_state.current_node = "hub_anchor_renner.sit">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_anchor_renner.sit") === -1) { vn.push("hub_anchor_renner.sit"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Head out.->Location_the_anchor]]<<set _costs to [{"trait": "energy", "value": 15}]>>\
<<if setup.checkCostsAffordable(_costs)>>\
<<script>>setup.deductCosts("work_depot_haul");<</script>>
<<set _sub_target = setup.checkAndSubstituteCanvas("work_depot_haul")>><<if _sub_target>><<goto _sub_target>><</if>>
<img src="./videos/activities/renner_menial.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She works the floor. Hauling, sorting, logging crates against a manifest that hasn't matched reality since Cain came through. It's dull, and her body doesn't tire the way a real one would, so she's better at it than the last three hands he ran off. The pay is thin, counted out grudging. But she does it well, and well is a language even a man this far gone still reads.</p>
<<set $game_state.current_canvas = "work_depot_haul">>
<<set $game_state.current_node = "work_depot_haul.base">>
<<script>>setup.markCanvasTriggered("work_depot_haul");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("work_depot_haul.base") === -1) { vn.push("work_depot_haul.base"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_renner", "relation", "add", 3.0, false, null);setup.applyAndNotifyTrait("player", null, "money", "add", 8.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "worked_renner_once", "set");<</script>>
[[Knock off for now.->Location_renner_depot]]
<<else>>
<div class="cost-blocked-message">
<p><<= setup.getCostBlockedMessage(_costs)>></p>
</div>
[[Back->Location_renner_depot]]
<</if>><<set _sub_target = setup.checkAndSubstituteCanvas("hub_depot_floor")>><<if _sub_target>><<goto _sub_target>><</if>>
<img src="./videos/scenes/renner_depot_floor.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Renner's depot. Half-empty racks, a forklift left broken, crates Cain's people left behind. He works the floor in a temper, and when he notices her at all it's to find fault. The work is the work.</p>
<<set $game_state.current_canvas = "hub_depot_floor">>
<<set $game_state.current_node = "hub_depot_floor.base">>
<<script>>setup.markCanvasTriggered("hub_depot_floor");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_depot_floor.base") === -1) { vn.push("hub_depot_floor.base"); }<</script>>
<<nobr>>
<<link "Check in with him." "Canvas_hub_depot_floor_Node_check_in">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_office_open", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 0}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('hub_depot_floor:cc0') ? '' : 'unlocked-choice'">
<<link "Tease him." "Canvas_rung_renner_tease_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "arousal", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_depot_floor:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Tease him.">Tease him. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<<else>>
<span class="locked-choice" title="Tease him.">Tease him.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_office_open", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 10}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('hub_depot_floor:cc1') ? '' : 'unlocked-choice'">
<<link "Flash him — work commando." "Canvas_rung_renner_flash_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "arousal", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_flirts_back", "set");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_depot_floor:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Flash him — work commando.">Flash him — work commando. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<<else>>
<span class="locked-choice" title="Flash him — work commando.">Flash him — work commando.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_office_open", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "renner_flirts_back", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 20}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('hub_depot_floor:cc2') ? '' : 'unlocked-choice'">
<<link "Get your hands on him." "Canvas_rung_renner_grope_Node_base">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_renner", "arousal", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_depot_floor:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Get your hands on him.">Get your hands on him. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<<else>>
<span class="locked-choice" title="Get your hands on him.">Get your hands on him.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "renner_office_open", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "renner_oral_once", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_renner", "trait_key": "corruption", "operator": "gte", "value": 40}]})>>
<span @class="setup.isChoiceVisited('hub_depot_floor:cc3') ? '' : 'unlocked-choice'">
<<link "Take him in the office." "Canvas_loop_renner_office_sex_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "renner_fucked_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("hub_depot_floor:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Take him in the office.">Take him in the office.</span><br>
<</if>>
<<link "Head out." "Location_the_waterfront">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She checks in. He grunts something about the manifest, eyes on the page. It's not much. But she lets him not-look, lets him get used to the shape of her in his yard. That's the work under the work.</p>
<<set $game_state.current_canvas = "hub_depot_floor">>
<<set $game_state.current_node = "hub_depot_floor.check_in">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("hub_depot_floor.check_in") === -1) { vn.push("hub_depot_floor.check_in"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Back to it.->Location_renner_depot]]<img src="./videos/scenes/renner_anchor.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The Anchor is the kind of bar that's given up on its own neon. Renner's at the end of it. A big man gone soft and sour, three drinks into the evening and looking like the fourth won't help. He keeps his eyes on the glass when she takes the stool beside him.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> Whatever you're selling, I'm broke. Whatever you're offering, I've had it.</div></div><p>She tells him she heard he's rebuilding. That she works cheap, doesn't ask questions, doesn't tire. He looks at her then. Not the way men look, the way a man counting his last dollars looks at a price that's almost low enough.</p><span id="cascade-b2-beat-1"><<linkreplace "Wait.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/renner.jpg" alt="Renner" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Renner</strong> ...Depot. Nine sharp. You're late, you're gone. You steal, I break your hands. Now buy your own drink or get off my stool.</div></div><p>He goes back to the glass. It isn't much. But she's in. Being in, day after day, until a man like this stops noticing she's there, is the whole way the job gets done.</p>[[Leave him to it.->Location_the_anchor]]
<</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_renner_hired">>
<<set $game_state.current_node = "cap_renner_hired.base">>
<<script>>setup.markCanvasTriggered("cap_renner_hired");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_renner_hired.base") === -1) { vn.push("cap_renner_hired.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "renner_hired", "set");<</script>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<p>He pulls out and finishes on her face, holding her there by the jaw until he's done, then letting go the way you drop a thing back in a drawer. He's already turned to the window.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_finish_facial_t5"] to ($game_state.media_cycle["sex_mercer_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_finish_facial_t5/c781f4d92a8.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_finish_facial_t5/c66861dfacf.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_finish_facial_t5/ce54fec1275.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_finish_facial_t5/incumbent.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<p>He finishes inside her, holds, pulls out in silence. His cum slides down the inside of her thigh. He wipes himself on a cloth from the drawer and checks the time.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_finish_inside_t5"] to ($game_state.media_cycle["sex_mercer_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_finish_inside_t5/c1bd134c597.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_finish_inside_t5/c152e84f955.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_finish_inside_t5/c306a472344.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_finish_inside_t5/c2090f3207c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<p>He finishes in her ass. Nothing comes. No give, no opening, no man-belonging-to-her. Just his weight and his cum and then his absence as he steps back. The same nothing as every time. She sets it aside with the other things kept off her list, and straightens up.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_finish_ass_t5"] to ($game_state.media_cycle["sex_mercer_finish_ass_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_finish_ass_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_finish_ass_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_finish_ass_t5/c01e4903748.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_finish_ass_t5/c1003e30c7b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_finish_ass_t5/c20597f54be.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_finish_ass_t5/c59293fd397.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<</if>>
<<set $game_state.current_canvas = "mercer_finisher">>
<<set $game_state.current_node = "mercer_finisher.climax">>
<<script>>setup.markCanvasTriggered("mercer_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_finisher.climax") === -1) { vn.push("mercer_finisher.climax"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
[[Straighten up.->Location_penthouse]]<p>He's already unbuckling when she crosses to him; there's never preamble. He uses her the way he uses anything he owns. Fully, unthanked, his mind somewhere else the whole time.</p>
<<set $game_state.current_canvas = "mercer_serve">>
<<set $game_state.current_node = "mercer_serve.intro">>
<<script>>setup.markCanvasTriggered("mercer_serve");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_serve.intro") === -1) { vn.push("mercer_serve.intro"); }<</script>>
<<nobr>>
<<link "Down on your knees." "Canvas_mercer_serve_Node_base_knees">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_serve_knees_t5"] to ($game_state.media_cycle["sex_mercer_serve_knees_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_serve_knees_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_serve_knees_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_serve_knees_t5/c0c758f63e7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_serve_knees_t5/c4415c30da2.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_serve_knees_t5/ca6b08d8802.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_serve_knees_t5/cffcdcc1184.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees on the floor, his cock in her mouth, his hand setting the pace by her hair. He watches the city and not her, talking to no one. A maintenance note, a time he wants a thing done. She services him.</p>
<<set $game_state.current_canvas = "mercer_serve">>
<<set $game_state.current_node = "mercer_serve.base_knees">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_serve.base_knees") === -1) { vn.push("mercer_serve.base_knees"); }<</script>>
<<nobr>>
<<link "Keep sucking his cock." "Canvas_mercer_serve_Node_base_knees">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Let him bend you over the desk." "Canvas_mercer_serve_Node_base_desk">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Present your ass against the glass." "Canvas_mercer_serve_Node_base_glass">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('mercer_serve:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_mercer_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("mercer_serve:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_serve_desk_t5"] to ($game_state.media_cycle["sex_mercer_serve_desk_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_serve_desk_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_serve_desk_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_serve_desk_t5/c9b1f3f6b50.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_serve_desk_t5/c43e89f51dc.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_serve_desk_t5/cfcf7381033.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_serve_desk_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Bent over the desk, his hand flat between her shoulder blades to keep her down, he fucks her from behind. Unhurried, proprietary. Her body answers the way it always does, and he notes that it does, the way you'd note a gauge reading true.</p>
<<set $game_state.current_canvas = "mercer_serve">>
<<set $game_state.current_node = "mercer_serve.base_desk">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_serve.base_desk") === -1) { vn.push("mercer_serve.base_desk"); }<</script>>
<<nobr>>
<<link "Take it." "Canvas_mercer_serve_Node_base_desk">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_mercer_serve_Node_base_knees">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Let him take your ass." "Canvas_mercer_serve_Node_base_glass">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('mercer_serve:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_mercer_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("mercer_serve:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_mercer_serve_glass_t5"] to ($game_state.media_cycle["sex_mercer_serve_glass_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_mercer_serve_glass_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_mercer_serve_glass_t5"]>><<if _mc is 0>><video src="./videos/sex/mercer_serve_glass_t5/c2e775e29e9.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/mercer_serve_glass_t5/cc32ed19646.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/mercer_serve_glass_t5/cee6a58b71d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/mercer_serve_glass_t5/incumbent.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Against the glass wall, the lit city laid out under them, he takes her ass in long deliberate strokes, both hands on her hips. This is the act that hands her the controls of any other man alive. She braces on the glass and waits to feel it start. The give, the opening. It doesn't come. It never comes with him.</p>
<<set $game_state.current_canvas = "mercer_serve">>
<<set $game_state.current_node = "mercer_serve.base_glass">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_serve.base_glass") === -1) { vn.push("mercer_serve.base_glass"); }<</script>>
<<nobr>>
<<link "Take it in the ass." "Canvas_mercer_serve_Node_base_glass">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back over the desk." "Canvas_mercer_serve_Node_base_desk">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('mercer_serve:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass." "Canvas_mercer_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("mercer_serve:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><img src="./videos/scenes/mercer_penthouse_hub.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Mercer's penthouse. He's at the desk or the glass, and whatever he's doing he can be interrupted to use her. That's what she's for, and they both know it. He looks up when she comes in. He doesn't smile. He never smiles.</p>
<<set $game_state.current_canvas = "mercer_penthouse_hub">>
<<set $game_state.current_node = "mercer_penthouse_hub.base">>
<<script>>setup.markCanvasTriggered("mercer_penthouse_hub");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_penthouse_hub.base") === -1) { vn.push("mercer_penthouse_hub.base"); }<</script>>
<<nobr>>
<<link "Report." "Canvas_mercer_penthouse_hub_Node_report">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Kneel and serve him." "Canvas_mercer_serve_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Leave." "Location_atrium">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She gives him what she has. The Renner approach, the angle, the timeline. He listens the way he listens to a status light: for whether it's green.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Don't bring me progress. Bring me the man's secrets or bring me nothing. Go make yourself useful to someone blind to what you are.</div></div>
<<set $game_state.current_canvas = "mercer_penthouse_hub">>
<<set $game_state.current_node = "mercer_penthouse_hub.report">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("mercer_penthouse_hub.report") === -1) { vn.push("mercer_penthouse_hub.report"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Go.->Location_penthouse]]<img src="./videos/scenes/mercer_penthouse.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The penthouse, by daylight. Mercer's at the glass with a tablet, and he stays facing the glass when the elevator lets her in. He doesn't have to. She's company-issue, and she's here because being here is what she's for.</p><span id="cascade-b2-beat-0"><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> On your knees. I've got a call in ten.</div></div><span id="cascade-b2-beat-1"><<linkreplace "Kneel.">><p>She goes down in silence. He takes the call one-handed, her mouth around his cock, the other hand resting in her hair the way a man rests his hand on a tool he isn't using yet. He finishes before the call does. She swallows, because that's tidy, and tidy is what's expected.</p><video src="./videos/sex/mercer_first_oral_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><span id="cascade-b2-beat-2"><<linkreplace "Hear the terms.">><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Good. You come up when I want you, and you're like this when you do. That's the arrangement. It was always the arrangement.</div></div><p>It was. She straightens, wipes her mouth, and the shape of the days settles over her. The same shape as all the days behind it: the cradle, the call, the kneeling. World without end.</p>[[Stand up.->Location_penthouse]]
<</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "cap_first_penthouse_service">>
<<set $game_state.current_node = "cap_first_penthouse_service.base">>
<<script>>setup.markCanvasTriggered("cap_first_penthouse_service");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cap_first_penthouse_service.base") === -1) { vn.push("cap_first_penthouse_service.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "mercer_hub_open", "set");<</script>><p>He comes, because he always comes. She has stopped pretending to herself that she works out when and started simply waiting for it, which takes a day and a half this time.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It went up. A man came down for it in a case with a lock on it and took it up the tower, and the man who watched that happen is forty minutes' walk from here and will not talk to you.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> No.</div></div><p>That is all of it. Not an argument, not a reason. A door closing. She has watched enough men close enough doors to know she is not getting this one open by pushing on it.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> I am not asking you to talk to him. I am asking you to stand in his room while he talks to me, because he has the half you have not got and you have the half he will never get, and I am the only thing either of you will let through a door.</div></div><p>He looks at the floor for a while, the way he looked at it on the end of her bunk, and then he picks his coat up off the bench and holds the door open. That is his entire answer.</p>
<<set $game_state.current_canvas = "activity_ask_him_to_come">>
<<set $game_state.current_node = "activity_ask_him_to_come.base">>
<<script>>setup.markCanvasTriggered("activity_ask_him_to_come");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_ask_him_to_come.base") === -1) { vn.push("activity_ask_him_to_come.base"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "cain_came_along", "set");<</script>>
[[Take him down the lane.->Location_grier_room]]<p>The stairwell goes down further than she expects and comes out somewhere she does not recognise, and he does not tell her where it is on the way and she does not ask him. Head down for the middle of it, the same as every other time.</p>
<<set $game_state.current_canvas = "activity_leave_somewhere">>
<<set $game_state.current_node = "activity_leave_somewhere.base">>
<<script>>setup.markCanvasTriggered("activity_leave_somewhere");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_leave_somewhere.base") === -1) { vn.push("activity_leave_somewhere.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
[[Home.->Location_the_cot]]<p>She does not have to stop this time. He said again, and he is not a man who says a thing twice, so all she has to do is be in the room on a night he is likely to look. She is in the room on the first one.</p><p>He comes in and does not sit down and does not take his coat off, and he waits, because this time there is a question on the floor between them and it is hers and not his.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Take me back.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Three words. She has spent nine years getting things out of men without ever once asking for anything, and it turns out asking takes about a second and a half.</div></div>
<<set $game_state.current_canvas = "activity_ask_him_back">>
<<set $game_state.current_node = "activity_ask_him_back.base">>
<<script>>setup.markCanvasTriggered("activity_ask_him_back");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_ask_him_back.base") === -1) { vn.push("activity_ask_him_back.base"); }<</script>>
<<script>>advanceTime(540);<</script>>
[[Go with him.->Location_room_no_name]]<p>There is no way to reach him. There has never been a way to reach him, in eleven years, and she sits on the bunk for a while working the problem the way she works every problem and gets nowhere at all with it.</p><p>So she does the only thing she has. She does not take a shift. She does not take the road to the Reach or the lift up the tower or the lane down to the lockup. She stays in, and the second day is worse than the first, and on the second night he is standing at the feed line with his coat on.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/cain.jpg" alt="Cain" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Cain</strong> Two days. I gave it three before I came and looked.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He has never once had to be told a thing about her. She has spent this whole chapter learning to read men and he has been doing it to her the entire time for free.</div></div>
<<set $game_state.current_canvas = "activity_say_yes">>
<<set $game_state.current_node = "activity_say_yes.base">>
<<script>>setup.markCanvasTriggered("activity_say_yes");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_say_yes.base") === -1) { vn.push("activity_say_yes.base"); }<</script>>
<<script>>advanceTime(2880);<</script>>
[[Go with him.->Location_room_no_name]]<p>The log is on its stand by the door and the pen is on a string, and the cold comes off the racks the whole way to the stairwell and stops at the threshold like it has been told to.</p>
<<set $game_state.current_canvas = "activity_leave_the_store">>
<<set $game_state.current_node = "activity_leave_the_store.base">>
<<script>>setup.markCanvasTriggered("activity_leave_the_store");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_leave_the_store.base") === -1) { vn.push("activity_leave_the_store.base"); }<</script>>
<<script>>advanceTime(5);<</script>>
[[Up to the floor.->Location_the_rise_floor]]<p>Two floors down instead of four. The stairwell is the same open concrete the whole way and the door at the bottom of it is the only door in this building anybody has bothered to finish.</p>
<<set $game_state.current_canvas = "activity_into_the_store">>
<<set $game_state.current_node = "activity_into_the_store.base">>
<<script>>setup.markCanvasTriggered("activity_into_the_store");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_into_the_store.base") === -1) { vn.push("activity_into_the_store.base"); }<</script>>
<<script>>advanceTime(5);<</script>>
[[Open it.->Location_the_dry_store]]<p>He is under the cradle with a torch when she comes down the boards, and he does not come out from under it, and he does not have to be told twice that she wants something built.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> A case. Sample case, company pattern, sealed, cold-rated. Eleven characters on the end of it that I will give you. Nothing inside it that has to be anything.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Nothing inside it. So it goes somewhere a thing already is, and the thing that's already there comes out. Don't tell me the room.</div></div><p>She tells him the room anyway, and the shelf, and the number on the front of the cabinet, because the number is the specification and there is no version of this where she keeps it from the man cutting the metal.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Then that's what it has to survive. Not a lock, not a man's eyes, a number on a dial. That's the easiest thing anybody's ever asked me to forge and I want you to hear me say that out loud before you pay for it.</div></div>
<<set $game_state.current_canvas = "kess_makes_the_blank">>
<<set $game_state.current_node = "kess_makes_the_blank.base">>
<<script>>setup.markCanvasTriggered("kess_makes_the_blank");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_makes_the_blank.base") === -1) { vn.push("kess_makes_the_blank.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 45}])>>
<<link "Have him make it. (45 coin.)" "Canvas_kess_makes_the_blank_Node_made">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "decoy_made", "set");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -45, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Have him make it. (45 coin.)">Have him make it. (45 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 45}])>>)</span><br>
<</if>>
<<link "Come back with the coin." "Location_kess_berth">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It takes him two hours and most of that is the label. The case comes off a hull he stripped in the spring, cut down, resealed, and cold-rated on a bench with a hose and a gauge until it holds the number she gave him with eleven degrees in hand.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Eleven characters. Count them yourself, twice, before you walk it in there. I've done nine and thought it was eleven before now and so has every man who ever made one of these.</div></div><p>Then he wipes it down, wraps it, and holds onto it for a second longer than he needs to when he hands it over.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/kess.jpg" alt="Kess" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Kess</strong> Understand what you're buying. That'll hold a dial forever. It holds a man exactly until the day one of them opens it up and reads it, and then it holds nothing at all and everybody who was in that log is in it.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He wants the method, not the contents. A man who can copy a thing has no reason to open it. She is buying months, and the number stays his.</div></div>
<<set $game_state.current_canvas = "kess_makes_the_blank">>
<<set $game_state.current_node = "kess_makes_the_blank.made">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("kess_makes_the_blank.made") === -1) { vn.push("kess_makes_the_blank.made"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Take it.->Location_kess_berth]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "npc_at_location", "location_id": "sabin_lab", "npc_id": "npc_sabin", "operator": "is_absent"}]})>>
<p>The lights are on because they are always on. The bench is where he left it, the stacks are where he left them, and her own footsteps go up into the open ceiling and come back off the glass a half-second later.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Nothing on this level shuts. Not a door, not a duct, not a partition. Anything done up here is done at whatever volume the building decides.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "npc_at_location", "location_id": "sabin_lab", "npc_id": "npc_sabin", "operator": "is_present"}]})>>
<p>He says something at the bench, aimed at the work rather than at her, and is still saying it when the stair door goes. He keeps his head down. It is not rudeness; he has simply not finished the sentence.</p>
<</if>>
<<set $game_state.current_canvas = "activity_leave_the_lab">>
<<set $game_state.current_node = "activity_leave_the_lab.base">>
<<script>>setup.markCanvasTriggered("activity_leave_the_lab");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_leave_the_lab.base") === -1) { vn.push("activity_leave_the_lab.base"); }<</script>>
<<script>>advanceTime(5);<</script>>
[[Down to the floor.->Location_the_rise_floor]]<p>The lift takes four floors in about nine seconds and opens on a level with the lights already on and the floor empty. Nobody comes up here. There is nothing on this floor to come up for except the man at the far end of it.</p>
<<set $game_state.current_canvas = "activity_up_to_the_lab">>
<<set $game_state.current_node = "activity_up_to_the_lab.base">>
<<script>>setup.markCanvasTriggered("activity_up_to_the_lab");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_up_to_the_lab.base") === -1) { vn.push("activity_up_to_the_lab.base"); }<</script>>
<<script>>advanceTime(5);<</script>>
[[Go down the room.->Location_sabin_lab]]<img src="./videos/activities/work_the_archive.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The work is eleven years of somebody else's notes in no order at all. Lab logs, procurement, three different hands, half of it scanned crooked. She is given a range of dates and told to say what is in it.</p><p>She is faster than the twenty other people on this floor and she is faster than she lets herself look. By the middle of the afternoon she has stopped reading the words and started reading the shape of them. That is not a thing she has ever had to explain to anybody.</p><p>Nobody talks. The ceiling is open above the desks and sound goes straight up into the vents, so even the coughing is polite.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sabin_suspects", "operator": "lt", "value": 3}]})>>
<p>Sabin comes down the row once in the afternoon with the mug and says the same thing he said the last time, and then goes back up the stairs with it still full.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Whatever it is you are doing, keep doing it. I do not need to understand it. Four months of this and you are the first thing that has gone right.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sabin_suspects", "operator": "gte", "value": 3}, {"type": "trait", "subject": "player", "trait_key": "sabin_suspects", "operator": "lt", "value": 6}]})>>
<p>He stops at the end of her desk on the way past now, and what he asks about is not the files. It is the reading itself. What order she goes in, and what she is looking at when she is not looking at the words.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> You are not scanning. I have watched people scan and it does not look like that. You go down a column and then you stop, and the stopping is the part I cannot account for.</div></div><p>She gives him an answer that is true and useless. Practice, and a good memory for shapes. He takes it, and nods, and writes something down on the corner of the sheet before he goes.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sabin_suspects", "operator": "gte", "value": 6}, {"type": "trait", "subject": "player", "trait_key": "sabin_suspects", "operator": "lt", "value": 9}]})>>
<p>He puts a page in front of her from well inside the range she was given. Older, a different hand, and half of it is a notation nobody outside a company lab has ever had a reason to be able to read.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Humour me. What does the second column say.</div></div><p>She reads it. It takes about four seconds, and she has answered out loud before the part of her that keeps her alive has caught up with the part of her that likes being good at things.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> Right. Yes. That is what it says.</div></div><p>He leaves it there. He takes the page back, and goes up to the lab, and she sits at that desk for the rest of the shift listening to the vents.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sabin_suspects", "operator": "gte", "value": 9}]})>>
<p>He lets a week go by before he asks her anything. Then he comes down the row on a Thursday and sits on the corner of her desk, which he has never done, and looks at her for a while before he starts.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> You read a notation you have never been taught. You correct my arithmetic in your head and then decide whether to mention it. Nine hours and you do not get tired, and you do not eat. I have been keeping a list.</div></div><p>He says all of it evenly, in order, the way he reads a column out. It takes about twenty seconds and there is nothing at all underneath it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/sabin.jpg" alt="Sabin" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Sabin</strong> I am going to stop keeping it. Whatever you were before this and whoever is paying for it is not in my fee. It has never once been in my fee. Be here at eight and read what I put in front of you.</div></div><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He has just said out loud, in order, every single thing he has noticed about her, and then put it down. Knowing would cost him a job he is paid very well to hold. He would rather not pay.</div></div>
<</if>>
<<set $game_state.current_canvas = "work_the_archive">>
<<set $game_state.current_node = "work_the_archive.base">>
<<script>>setup.markCanvasTriggered("work_the_archive");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("work_the_archive.base") === -1) { vn.push("work_the_archive.base"); }<</script>>
<<script>>advanceTime(240);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);setup.applyAndNotifyTrait("player", null, "sabin_suspects", "add", 1.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "archive_worked", "set");<</script>>
[[Sign out.->Location_the_rise_floor]]<p>The lift works and the stairs are open concrete and both come out at the same desk with the same man reading behind it. He keeps his head down on the way out too.</p>
<<set $game_state.current_canvas = "activity_leave_the_rise">>
<<set $game_state.current_node = "activity_leave_the_rise.base">>
<<script>>setup.markCanvasTriggered("activity_leave_the_rise");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_leave_the_rise.base") === -1) { vn.push("activity_leave_the_rise.base"); }<</script>>
<<script>>advanceTime(10);<</script>>
[[Out onto the plaza.->Location_spire_plaza]]<img src="./videos/locations/underworld_market.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The same three curtained tables at the end of the row, and the same woman behind them, and not one sign anywhere on her that she recognises a face she cut herself.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> Not a face this time. A history. Somewhere that trained me, somewhere that had me for two years, and a card that gets looked at once by a floor that is hiring in a hurry.</div></div><p>The woman pulls a drawer out from under the table and sets three blanks on the cloth and lets the question sit. That is how she says yes.</p><p>"Readers," she says. "You want the Rise. Everybody who has asked me for this in a month wants the Rise, and none of you can read half as fast as you all think you can."</p>
<<set $game_state.current_canvas = "activity_buy_papers">>
<<set $game_state.current_node = "activity_buy_papers.base">>
<<script>>setup.markCanvasTriggered("activity_buy_papers");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_papers.base") === -1) { vn.push("activity_buy_papers.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 60}])>>
<<link "Buy the credential. (60 coin.)" "Canvas_activity_buy_papers_Node_buy">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "papers_bought", "set");<</script>><<script>>setup.addToWardrobe("cover_research");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -60, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Buy the credential. (60 coin.)">Buy the credential. (60 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 60}])>>)</span><br>
<</if>>
<<link "Not yet." "Location_underworld_market">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It takes an hour and a half, and all of it is done to the paper. The woman works at a bench under a lamp with a scalpel and a stack of blanks, and the only part that needs Wren at all is holding still for the picture.</p><p>"The hand on these is not mine," she says, not looking up. "There is a man down here now who came out of the towers last winter with nothing on him but what he knew about paper. You are paying for his week, mostly, and he does not want to be thanked."</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> She knows exactly one man who came down out of the Spire last winter with only what he knew. She does not ask.</div></div><p>What she takes away is a card in a sleeve, two years of employment somewhere that has never existed, and a bag of clothes cut for a floor where nobody does anything at all with their hands.</p>
<<set $game_state.current_canvas = "activity_buy_papers">>
<<set $game_state.current_node = "activity_buy_papers.buy">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_papers.buy") === -1) { vn.push("activity_buy_papers.buy"); }<</script>>
<<script>>advanceTime(90);<</script>>
[[Take it back to the berth.->Location_underworld_market]]<p>The bolt turns. One cubicle, one cracked basin, a hook on the back of the door, and the bar coming through the wall at the volume it comes through everything down here.</p>
<<set $game_state.current_canvas = "activity_bar_change">>
<<set $game_state.current_node = "activity_bar_change.base">>
<<script>>setup.markCanvasTriggered("activity_bar_change");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_change.base") === -1) { vn.push("activity_bar_change.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('activity_bar_change:cc0') ? '' : 'unlocked-choice'">
<<link "Change into the dress." "Canvas_activity_bar_change_Node_into">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.addToWardrobe("dress_undertow"); setup.equipItem("dress_undertow");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_bar_change:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Out of the face she is Wren, and Wren does not work here — Sol hired a stranger, and the dress belongs to the stranger. Put it on at the cot first.">Out of the face she is Wren, and Wren does not work here — Sol hired a stranger, and the dress belongs to the stranger. Put it on at the cot first.</span><br>
<</if>>
<<link "Back into your own things." "Canvas_activity_bar_change_Node_out">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.addToWardrobe("cover_stranger"); setup.equipItem("cover_stranger");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Leave it." "Location_underworld_bar_bathroom">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It goes on over the head and is the right size, which she has stopped finding interesting and has not stopped noticing. Her own things fold small enough to sit on the hook under her coat.</p>
<<set $game_state.current_canvas = "activity_bar_change">>
<<set $game_state.current_node = "activity_bar_change.into">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_change.into") === -1) { vn.push("activity_bar_change.into"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Out onto the floor.->Location_underworld_bar_bathroom]]<p>The dress goes on the hook where the bag was and stays in the building, because it is not hers and it has never once left with her. Her own kit smells of the strip and of the cot and of nothing anybody chose for her.</p>
<<set $game_state.current_canvas = "activity_bar_change">>
<<set $game_state.current_node = "activity_bar_change.out">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_change.out") === -1) { vn.push("activity_bar_change.out"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Out.->Location_underworld_bar_bathroom]]<p>The emitter comes out of her bag and onto the flat of the cot, casing off, guts open. Kess's bench is twenty feet away and it is not hers to use. She knows the architecture of this thing the way she knows her own, because it is her own, scaled down to a handheld.</p>
<<set $game_state.current_canvas = "activity_repair_weapon_cot">>
<<set $game_state.current_node = "activity_repair_weapon_cot.base">>
<<script>>setup.markCanvasTriggered("activity_repair_weapon_cot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_repair_weapon_cot.base") === -1) { vn.push("activity_repair_weapon_cot.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "lt", "value": 2}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_repair_weapon_cot:cc0') ? '' : 'unlocked-choice'">
<<link "Work on it." "Canvas_activity_repair_weapon_cot_Node_progress">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "weapon_repair", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_repair_weapon_cot:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work on it.">Work on it. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "lt", "value": 3}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_repair_weapon_cot:cc1') ? '' : 'unlocked-choice'">
<<link "Finish it." "Canvas_activity_repair_weapon_cot_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "weapon_repair", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "arousal_weapon_ready", "set");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_repair_weapon_cot:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Finish it.">Finish it. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<link "Leave it for now." "Location_the_cot">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "lt", "value": 2}]})>>
<p>She straightens the field coils, one pass, and tests the draw. Dead still. Cleaner dead than it was. More to do.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "gte", "value": 2}]})>>
<p>Driver reseated, coils true. It draws a charge now and holds it. A flicker of the field crossing her own skin, the faint unwanted warmth of it. Almost. One more pass and it fires.</p>
<</if>>
<<set $game_state.current_canvas = "activity_repair_weapon_cot">>
<<set $game_state.current_node = "activity_repair_weapon_cot.progress">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_repair_weapon_cot.progress") === -1) { vn.push("activity_repair_weapon_cot.progress"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Set it down.->Location_the_cot]]<p>Last pass. She powers it and the field comes up clean, a low hum she feels in her teeth. She tests it on herself a half-second too long and gets a heat low in her belly she didn't ask for. She shuts it off fast. It works. A second weapon now, hers, that the company never issued and cannot take back.</p>
<<set $game_state.current_canvas = "activity_repair_weapon_cot">>
<<set $game_state.current_node = "activity_repair_weapon_cot.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_repair_weapon_cot.done") === -1) { vn.push("activity_repair_weapon_cot.done"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Stow it.->Location_the_cot]]<p>Concrete floor, a stripped hull for a wall, and nobody down here who minds what she does with an hour. She drills the body they built out of her in a yard that takes machines apart for a living. Kess does not look up once.</p>
<<set $game_state.current_canvas = "activity_train_cot">>
<<set $game_state.current_node = "activity_train_cot.base">>
<<script>>setup.markCanvasTriggered("activity_train_cot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_train_cot.base") === -1) { vn.push("activity_train_cot.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "lt", "value": 30}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train_cot:cc0') ? '' : 'unlocked-choice'">
<<link "Combat drill." "Canvas_activity_train_cot_Node_combat">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train_cot:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Combat drill.">Combat drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 30}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "lt", "value": 50}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train_cot:cc1') ? '' : 'unlocked-choice'">
<<link "Combat drill." "Canvas_activity_train_cot_Node_combat">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train_cot:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Combat drill.">Combat drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "yard_caught_once", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 30}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train_cot:cc2') ? '' : 'unlocked-choice'">
<<link "Stealth drill." "Canvas_activity_train_cot_Node_stealth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train_cot:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Stealth drill.">Stealth drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "yard_caught_once", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 30}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 50}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train_cot:cc3') ? '' : 'unlocked-choice'">
<<link "Stealth drill." "Canvas_activity_train_cot_Node_stealth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train_cot:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Stealth drill.">Stealth drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<link "Enough for now." "Location_the_cot">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "lt", "value": 25}]})>>
<p>She runs the forms against the empty air. Strikes, breaks, the throw that ends a man. Her body obeys a half-beat slow, the way a tool obeys before it's been worked hard. Clumsy still. But the half-beat is shorter than it was yesterday.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 25}]})>>
<p>No hesitation now. The forms come fast and flat and final. Strike, break, the throw. Each one lands where a throat or a knee would be. Whatever they built her for, this wasn't on the spec. She's better than the file says. She keeps that to herself.</p>
<</if>>
<<set $game_state.current_canvas = "activity_train_cot">>
<<set $game_state.current_node = "activity_train_cot.combat">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_train_cot.combat") === -1) { vn.push("activity_train_cot.combat"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Rack it. Catch your breath.->Location_the_cot]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}]})>>
<p>She practices the small things. Weight rolled onto the outside of the foot, breath dropped low, the timing of a turned back. Her own joints betray her with a tick of sound she'd never have caught a week ago. She catches it now. That's the start of it.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 25}]})>>
<p>She moves the length of the dock and nothing registers her. No sound off the wet concrete, no shift of air, nothing for a camera to hold. A thing that can't be seen goes where it likes. She doesn't let the thought finish.</p>
<</if>>
<<set $game_state.current_canvas = "activity_train_cot">>
<<set $game_state.current_node = "activity_train_cot.stealth">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_train_cot.stealth") === -1) { vn.push("activity_train_cot.stealth"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Ease off. Settle.->Location_the_cot]]<p>There is a tap past the hull and a drain in the concrete under it, and the water comes off the same line that charges her. She strips in a working dock with Kess forty feet off and his back turned, and gets the day off standing up. Cold the whole way through, and hers.</p>
<<set $game_state.current_canvas = "activity_wash_cot">>
<<set $game_state.current_node = "activity_wash_cot.base">>
<<script>>setup.markCanvasTriggered("activity_wash_cot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_wash_cot.base") === -1) { vn.push("activity_wash_cot.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "hygiene", "add", 100.0, true, null);setup.showEffectNotification();<</script>>
[[Dry off. Dressed.->Location_the_cot]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_false"}]})>>
<p>The bag is under the cot where it lives. Twenty minutes at the cracked glass over the basin and she is somebody else. She has the order of it now, and her hands do most of it on their own.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_true"}]})>>
<p>She is wearing it now, in her own room, with the door shut and the room empty. It comes off in about a minute and goes back on in twenty. That is the exchange rate on being nobody.</p>
<</if>>
<<set $game_state.current_canvas = "activity_the_face">>
<<set $game_state.current_node = "activity_the_face.base">>
<<script>>setup.markCanvasTriggered("activity_the_face");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_the_face.base") === -1) { vn.push("activity_the_face.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('activity_the_face:cc0') ? '' : 'unlocked-choice'">
<<link "Put it on." "Canvas_activity_the_face_Node_on">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_worn", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_the_face:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('activity_the_face:cc1') ? '' : 'unlocked-choice'">
<<link "Take it off." "Canvas_activity_the_face_Node_off">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_worn", "unset");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_the_face:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave it." "Location_the_cot">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The order of it is fixed now: the hairline first, then the jaw, then the small dull work around the eyes that does more than any of the rest. She looks at the whole of it only at the end.</p><p>The woman in the glass has a job at a bar off the strip, no history anybody has asked about, and nothing at all to do with a programme that closed eleven years ago.</p>
<<set $game_state.current_canvas = "activity_the_face">>
<<set $game_state.current_node = "activity_the_face.on">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_the_face.on") === -1) { vn.push("activity_the_face.on"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Go to work.->Location_the_cot]]<p>It comes off faster than it goes on. A minute at the basin, the water going grey, and the woman who has been carrying trays for a man who owned her stops existing over a cracked sink in a ship-breaker's yard.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Nothing out there is hers while this is off. Sol does not know her. The floor is not her floor and the roster does not have her on it, and the room behind the door is a room she has never been invited into. All of that belongs to a woman with no name who does not exist until she puts it back on.</div></div><p>She does it anyway, most nights, for an hour, and would struggle to give a reason that survives being said out loud.</p><p>The face in the glass is four years older than the paperwork says and has a designation on a page in a file under the cot, and it is the only thing in this city that nobody sold her.</p>
<<set $game_state.current_canvas = "activity_the_face">>
<<set $game_state.current_node = "activity_the_face.off">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_the_face.off") === -1) { vn.push("activity_the_face.off"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Sit with it a while.->Location_the_cot]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "grier_met", "operator": "is_false"}]})>>
<p>A name and a district is not an address. She spends an afternoon on it and it costs her the afternoon and only that. Old men in the Reach are a small list, and a machinist who stopped is a shorter one.</p><p>Third try, a ship's supplier on the water gives it up unpushed: a lockup off the back lane, roller door, chained from the inside. He says the name like it is a thing that used to be worth something.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "grier_met", "operator": "is_true"}]})>>
<p>Off the water, up the back lane, past the bins and the dead van. The roller door is down the way it is always down, and the side door hangs open, because the contents are worthless.</p>
<</if>>
<<set $game_state.current_canvas = "activity_go_to_grier">>
<<set $game_state.current_node = "activity_go_to_grier.base">>
<<script>>setup.markCanvasTriggered("activity_go_to_grier");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_go_to_grier.base") === -1) { vn.push("activity_go_to_grier.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Knock.->Location_grier_room]]<img src="./videos/locations/the_anchor.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Grier pours another one and does not offer her any. That is the whole of the hour, every time, and it has been the whole of the hour for a month. He drinks his own and she sits and watches him do it.</p><p>The Anchor keeps the bottom shelf for men who have stopped tasting it. Twenty coin, which is what a part costs, for something he will be through by dark. The bartender puts it on the wood and does not ask who it is for.</p>
<<set $game_state.current_canvas = "activity_buy_bottle">>
<<set $game_state.current_node = "activity_buy_bottle.base">>
<<script>>setup.markCanvasTriggered("activity_buy_bottle");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_bottle.base") === -1) { vn.push("activity_buy_bottle.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 20}])>>
<<link "Buy a bottle. (20 coin.)" "Canvas_activity_buy_bottle_Node_buy">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "bottle_held", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -20, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Buy a bottle. (20 coin.)">Buy a bottle. (20 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 20}])>>)</span><br>
<</if>>
<<link "Leave it on the shelf." "Location_the_anchor">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It is a squat brown thing with a label that has been printed crooked and a cap that turns too easily. Nothing about it is good. It is the same shelf he has been drinking off for nine years.</p><p>It goes in the inside pocket of her coat, where the weight of it sits against her ribs the whole way down the lane.</p>
<<set $game_state.current_canvas = "activity_buy_bottle">>
<<set $game_state.current_node = "activity_buy_bottle.buy">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_bottle.buy") === -1) { vn.push("activity_buy_bottle.buy"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Out.->Location_the_anchor]]<img src="./videos/activities/chip_view_cot.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "pieces_seated", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_false"}]})>>
<p>She opens the store the company gave her for what it calls recovered assets. Empty, the way it has always been empty. One slot in it, greyed out, labelled in a hand that is not the company's: FRAGMENT 01 — LOCKED.</p><p>They stripped her floor. They sealed the building behind her and put her face on every camera at the curb. They did not take this. She works out why on the second pass: it was never in the building.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "pieces_seated", "operator": "lt", "value": 1}, {"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_true"}]})>>
<p>She opens the store. Empty. FRAGMENT 01 sits greyed at the top of it in handwriting she does not remember using. She closes it, and notes again that she opens it more often than any task log would justify.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "pieces_seated", "operator": "eq", "value": 1}]})>>
<p>The slot is lit. Not greyed. Lit, with a size on the counter beside it and a date column that has stopped being blank. FRAGMENT 01, in her own handwriting, holding something at last.</p><p>She opens it. The data is there, and it is intact, and reading it does nothing at all. It is a clean file about somebody she has never met, and the somebody is her.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "pieces_seated", "operator": "gte", "value": 2}]})>>
<p>Two of them lit now, side by side. The first still says FRAGMENT 01 in her own hand. The second carries no label at all, because nobody ever gave her a night quiet enough to write one.</p><p>Both intact. Both hers. Both about as much use to her as a stranger's file left open on a bench, and she has stopped expecting that to change. That is its own kind of answer.</p>
<</if>>
<<set $game_state.current_canvas = "canvas_chip_view_cot">>
<<set $game_state.current_node = "canvas_chip_view_cot.base">>
<<script>>setup.markCanvasTriggered("canvas_chip_view_cot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_chip_view_cot.base") === -1) { vn.push("canvas_chip_view_cot.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_false"}]})>>
<span @class="setup.isChoiceVisited('canvas_chip_view_cot:cc0') ? '' : 'unlocked-choice'">
<<link "Close it." "Location_the_cot">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "store_carried_seen", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("canvas_chip_view_cot:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('canvas_chip_view_cot:cc1') ? '' : 'unlocked-choice'">
<<link "Close it." "Location_the_cot">><<script>>setup.markChoiceVisited("canvas_chip_view_cot:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_false"}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_true"}]})))>>
<<script>>
try {
window._engineNoExitsDiag_canvas_chip_view_cot = [{"text": "Close it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_false"}]}}, {"text": "Close it.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "store_carried_seen", "operator": "is_true"}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "canvas_chip_view_cot",
choices: window._engineNoExitsDiag_canvas_chip_view_cot,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_canvas_chip_view_cot>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas canvas_chip_view_cot</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Location_the_cot]]
<</if>>
<</nobr>><img src="./videos/scenes/backroom_ruin.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The Undertow opens days only now. Sol is in it most days with a shovel and a bucket and no particular plan, and he lets her past the tape because she is the only one of the staff who came back at all.</p><p>The back door is off its frame. What is behind it is a burned floor two inches deep in other people's paperwork, and most of it is worth exactly what it looks like.</p>
<<set $game_state.current_canvas = "activity_sift_the_ruin">>
<<set $game_state.current_node = "activity_sift_the_ruin.base">>
<<script>>setup.markCanvasTriggered("activity_sift_the_ruin");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_sift_the_ruin.base") === -1) { vn.push("activity_sift_the_ruin.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 10}])>>
<<link "Sift it. (An hour on your knees.)" "Canvas_activity_sift_the_ruin_Node_sift">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "ruin_depth", "add", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -10, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Sift it. (An hour on your knees.)">Sift it. (An hour on your knees.) (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 10}])>>)</span><br>
<</if>>
<<link "Leave it for today." "Location_underworld_bar">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "ruin_depth", "operator": "lt", "value": 2}]})>>
<p>An hour on her knees in wet ash. Manifests, bills of lading, a decade of somebody moving cargo that was never cargo. All of it worthless and all of it his, and none of it what he was actually keeping.</p><p>The spines with the dates on them are gone. Not burned. Gone. Somebody lifted whole years off that wall before the fire and the fire was for the rest.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "ruin_depth", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "ruin_depth", "operator": "lt", "value": 4}]})>>
<p>Under the desk, where the desk protected it, half a folder with the top third burned off. Vance paper. A transfer of custody, eleven years old, and a designation in the same format as her own.</p><p>It is not hers. She checks it four times against a number she has read exactly once and will never need to read again. The second date column on that sheet is filled in.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "ruin_depth", "operator": "gte", "value": 4}]})>>
<p>She goes back through it in daylight, and then again, and what she has at the end of it is nine sheets that mean anything and a coat that smells of burned paper for a fortnight.</p><p>Nine designations in her own format. Six of them have a date in the second column. Two do not. One of them is a line she has read before, on a bench, at a breaking dock, with a man standing over there pretending not to look.</p><p>There is nothing in any of it about where a man might live, and nothing in any of it about who came back eight months after the programme closed and sealed one page. That is not in this room. That was never going to be in this room.</p>
<</if>>
<<set $game_state.current_canvas = "activity_sift_the_ruin">>
<<set $game_state.current_node = "activity_sift_the_ruin.sift">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_sift_the_ruin.sift") === -1) { vn.push("activity_sift_the_ruin.sift"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Take what there is.->Location_underworld_bar]]<img src="./videos/locations/underworld_market.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The blade tables want forty and she has stood at them twice and walked off twice, because a knife in that room is a thing she would have to be willing to use on a man she needs conscious.</p><p>What she is actually short of is the emitter, and the emitter is not an option. One core feeds one weapon and the drain has to be the one that is live, every night she goes in. A Vance field unit in her coat would come out of it at the door, in front of the room, in a man's hand.</p><p>So: the box at the end of the row with the cheap gear in it, where a hand-taser is thirty coin and every woman working a floor down here has one.</p>
<<set $game_state.current_canvas = "activity_buy_taser">>
<<set $game_state.current_node = "activity_buy_taser.base">>
<<script>>setup.markCanvasTriggered("activity_buy_taser");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_taser.base") === -1) { vn.push("activity_buy_taser.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 30}])>>
<<link "Buy the taser. (30 coin.)" "Canvas_activity_buy_taser_Node_buy">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "taser_held", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -30, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Buy the taser. (30 coin.)">Buy the taser. (30 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 30}])>>)</span><br>
<</if>>
<<link "Leave it." "Location_underworld_market">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It is a grey plastic thing the size of her palm with a thumb-switch and a charge light that does not work. The man selling it takes her coin and leaves the question alone, because down here nobody has ever had to explain that one.</p><p>It goes in the coat, in the lining, where he is going to look.</p>
<<set $game_state.current_canvas = "activity_buy_taser">>
<<set $game_state.current_node = "activity_buy_taser.buy">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_taser.buy") === -1) { vn.push("activity_buy_taser.buy"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Take it to work.->Location_underworld_market]]<img src="./videos/locations/underworld_bar.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 2}]})>>
<p>Glasses, tables, the three steps with a full tray. Nobody looks at her and nobody speaks to her except to want something, which after a life of being the most interesting thing in every room she is in is close to restful.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 3}]})>>
<p>Behind the taps now. That is a different job entirely. Everything said in this room gets said at the counter eventually, and Sol has spent thirty years standing here hearing all of it and repeating none.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 3}, {"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 4}]})>>
<p>Back on the floor, in what came down from the back room in a bag with no note. Sol handed it over in silence and without meeting her eye, which told her whose bag it was more clearly than a note would have.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 4}]})>>
<p>The floor, the tray, the three steps, same as the first night. The only thing that has changed is that the door at the back opens for her now, and every man in this room who has noticed that has stopped looking at her twice.</p>
<</if>>
<<set $game_state.current_canvas = "activity_bar_work">>
<<set $game_state.current_node = "activity_bar_work.base">>
<<script>>setup.markCanvasTriggered("activity_bar_work");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_work.base") === -1) { vn.push("activity_bar_work.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 2}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_bar_work:cc0') ? '' : 'unlocked-choice'">
<<link "Work the floor. (15 coin.)" "Canvas_activity_bar_work_Node_shift">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_bar_work:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work the floor. (15 coin.)">Work the floor. (15 coin.) (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 3}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_bar_work:cc1') ? '' : 'unlocked-choice'">
<<link "Work the counter. (15 coin.)" "Canvas_activity_bar_work_Node_shift">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_bar_work:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work the counter. (15 coin.)">Work the counter. (15 coin.) (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 3}, {"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 4}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_bar_work:cc2') ? '' : 'unlocked-choice'">
<<link "Work the floor in what he sent down. (15 coin.)" "Canvas_activity_bar_work_Node_shift">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_bar_work:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work the floor in what he sent down. (15 coin.)">Work the floor in what he sent down. (15 coin.) (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 4}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_bar_work:cc3') ? '' : 'unlocked-choice'">
<<link "Work the floor. (15 coin.)" "Canvas_activity_bar_work_Node_shift">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 15.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_bar_work:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work the floor. (15 coin.)">Work the floor. (15 coin.) (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<link "Not tonight." "Location_underworld_bar">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 2}]})>>
<p>Six hours of it. Her hands go raw in the water and her back finds the exact place three steps with a loaded tray puts the weight, and she learns the room the way you only learn a room by carrying things across it.</p><p>Twice in the night the back door opens and closes and she keeps her back to it, because the girls who turn round are the ones Sol talks to afterwards.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 3}]})>>
<p>The taps, the till, and the whole room's talk arriving at her elbow in pieces. Most of it is nothing. She keeps the pieces that are about the back door and there are more of them than she expected.</p><p>Men go in with envelopes and come out without them. Nobody carries anything out. Whatever that room is, it takes paper in one direction only, and it has been doing it for years.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 3}, {"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "lt", "value": 4}]})>>
<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_bar_floor_handled_t4"] to ($game_state.media_cycle["sex_bar_floor_handled_t4"] === undefined ? 0 : ($game_state.media_cycle["sex_bar_floor_handled_t4"] + 1) % 3)>><<set _mc to $game_state.media_cycle["sex_bar_floor_handled_t4"]>><<if _mc is 0>><video src="./videos/sex/bar_floor_handled_t4/bar_floor_handled_t4a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/bar_floor_handled_t4/c7b2257f0d0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/bar_floor_handled_t4/c4583743a42.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>The dress is short and the material is thin and it was cut for a woman standing still. That is not what the job is. Bending for the low tables is the whole of the arithmetic and everyone in the room has done it.</p><p>Hands land. Not often and never hard. A palm flat on her ass while she reaches across, a hand up under the hem that finds her cunt through nothing at all and is gone before she straightens, knuckles dragging her tits through the thin material as she leans past. She sets the glasses down and moves on and it costs her nothing, and that is the part she notices.</p><p>Nobody goes further than that. They look at the back door first, every one of them, and then they take their hand back.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "bar_rung", "operator": "gte", "value": 4}]})>>
<p>Nobody's hand goes anywhere near her now. The dress is the same dress and the tables are the same height, and the whole room has quietly agreed she is off limits now.</p><p>It is not respect. It is the same instinct that makes them all check the back door first, arriving one step earlier.</p>
<</if>>
<<set $game_state.current_canvas = "activity_bar_work">>
<<set $game_state.current_node = "activity_bar_work.shift">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_work.shift") === -1) { vn.push("activity_bar_work.shift"); }<</script>>
<<script>>advanceTime(240);<</script>>
[[Close out.->Location_underworld_bar]]<img src="./videos/locations/underworld_market.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Past the blades, past the drawers of dead components, past the pens. The last three tables are curtained on three sides and the woman behind them does not sell anything you can hold up to the light.</p><p>She deals in the paperwork of being somebody. A face, a history thin enough not to check and thick enough not to ask about, and the clothes that make a stranger believe both unprompted.</p><p>The price is the price. She does not haggle and she does not explain what any of it costs her to arrange.</p>
<<set $game_state.current_canvas = "activity_buy_face">>
<<set $game_state.current_node = "activity_buy_face.base">>
<<script>>setup.markCanvasTriggered("activity_buy_face");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_face.base") === -1) { vn.push("activity_buy_face.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 120}])>>
<<link "Buy the face. (120 coin.)" "Canvas_activity_buy_face_Node_buy">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "face_bought", "set");<</script>><<script>>setup.addToWardrobe("cover_stranger");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -120, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Buy the face. (120 coin.)">Buy the face. (120 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 120}])>>)</span><br>
<</if>>
<<link "Not yet." "Location_underworld_market">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>It takes the afternoon and most of it is sitting still. The woman works close, in silence, the way Kess works, and asks her exactly one question. That is whether anyone has ever taken a print of her.</p><p>She says no. It is the first lie the face tells and it is told before the face exists.</p><p>What comes out at the end is not a mask and does not feel like one. It is a set of small differences that add up to somebody else, and a bag of clothes that belong to the somebody else rather than to her.</p><p>"Don't wear it in front of anyone who knew the old one," the woman says, folding the bag shut. "That's not me being careful. That's the whole of what you paid for."</p>
<<set $game_state.current_canvas = "activity_buy_face">>
<<set $game_state.current_node = "activity_buy_face.buy">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_face.buy") === -1) { vn.push("activity_buy_face.buy"); }<</script>>
<<script>>advanceTime(90);<</script>>
[[Take it back to the berth.->Location_underworld_market]]<p>There is nothing in the room to do. There are three things in it to notice.</p>
<<set $game_state.current_canvas = "cell_attend">>
<<set $game_state.current_node = "cell_attend.base">>
<<script>>setup.markCanvasTriggered("cell_attend");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_attend.base") === -1) { vn.push("cell_attend.base"); }<</script>>
<<nobr>>
<<link "Listen at the door." "Canvas_cell_attend_Node_listen">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Watch the man on the chair." "Canvas_cell_attend_Node_watch">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Hold still and feel the fault." "Canvas_cell_attend_Node_hold_still">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Steel carries. She sits with her shoulder against it and counts: five voices, six, one that comes and goes and never finishes a sentence because the others stop talking when it does. Cards, some nights. A radio. A long argument about a boat that she thinks is not about a boat.</p><p>Nothing about her. That's the part she keeps turning over. Whatever she is to them, she is beneath discussing.</p>
<<set $game_state.current_canvas = "cell_attend">>
<<set $game_state.current_node = "cell_attend.listen">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_attend.listen") === -1) { vn.push("cell_attend.listen"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Sit back.->Location_captive_room]]<p>There's always one, and it's always the chair. He doesn't talk to her. He reads, or he doesn't, and he watches the way a man watches a pot. When she looks back at him he holds it, bored, and eventually she is the one who looks away, and she notes that too, because a month ago she would not have.</p><p>Sometimes it's Bastien in the chair. He never reads. He sits with his hands still and studies her the way he studied her across the table, patient, waiting for the answer to a question he has not asked again.</p>
<<set $game_state.current_canvas = "cell_attend">>
<<set $game_state.current_node = "cell_attend.watch">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_attend.watch") === -1) { vn.push("cell_attend.watch"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Look away.->Location_captive_room]]<p>She lies on her back and stops doing anything at all, and listens to herself the way she listened to the door. The charge sits under her sternum with nowhere to be. It has a sound. It has, she realises, started to have a smell. Hot dust, the inside of a machine that has been run too long.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "glitch_iii_seen", "operator": "is_false"}]})>>
<p>And then the fault opens, the way a badly-set bone opens, and something comes up through it that was never filed anywhere she can reach.</p><p>A hand at the back of her neck. Not holding her. Resting there, the thumb moving once, slowly, along the seam. Somebody standing behind her while she looks at something she cannot see, and in the whole of her body, in the whole of the record, no fear at all. Not permitted absence of fear. The other kind. The kind that is simply not there because there is nothing in the room that could hurt her.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> Whose hand.</div></div><p>It closes. It goes back down wherever it lives. She lies in a room she cannot leave with men on the other side of the door and she finds that she is holding the back of her own neck, and that her eyes have gone wet, and that she has no idea, none, whose hand that was.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "glitch_iii_seen", "operator": "is_true"}]})>>
<p>She reaches for it again. The hand, the seam, the quiet. It isn't there. The fault opens once for a thing, and once only. What's left is the pressure, and the hot-dust smell, and the certainty that it is worse than it was.</p>
<</if>>
<<set $game_state.current_canvas = "cell_attend">>
<<set $game_state.current_node = "cell_attend.hold_still">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_attend.hold_still") === -1) { vn.push("cell_attend.hold_still"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "glitch_iii_seen", "set");<</script>>
[[Let it go.->Location_captive_room]]<p>The light doesn't go off, so she turns her face to the wall and powers down anyway. The bed is bolted down and the mattress smells of other people. She goes under fast, the way she always does, and the door opens in the night anyway. It always opens in the night.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "core_strain", "operator": "lt", "value": 24}]})>>
<video src="./videos/sex/cell_sleep_nominal_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She's down on the mat with her back to the wall, trying to drop under, when the weight settles in behind her and Bastien starts using her before she's all the way awake. His cock works into her cunt from behind, unhurried, one hand laid flat on the sternum plate so he can feel it tick while he does it. The charge climbs with every slow shove and runs down to the empty socket at the base of her spine and stops there, nowhere to go, stacking behind the plate in the dark.</p><p>He finishes inside her and the readout clicks up one notch and holds. It never drops. He wipes off on the small of her back and leaves her where she lies. <em>Logged as rest. It isn't.</em></p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Don't mind me. Go back under, filthy thing. I'm just reading you.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> There it goes. One more on the count and nowhere for it to run. Bought that too.</div></div>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "core_strain", "operator": "gte", "value": 24}, {"type": "trait", "subject": "player", "trait_key": "core_strain", "operator": "lt", "value": 48}]})>>
<video src="./videos/sex/cell_sleep_hot_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>She surfaces because there are hands on her that aren't one man's. The crew have let themselves in in the dark, and she wakes already being used, a cock working her cunt while another feeds itself into her mouth and a third pair of hands just paws her tits like they're checking she's still warm. She can't tell how many; they pass her between them in the black, laughing low, and every load that goes in stacks up behind the plate with the drain gone and the socket empty, filling and filling with nowhere to send it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Left the door open for the lads. She sleeps better with a hole full — don't you, slut.</div></div><p>"She's awake. Watch. The little machine's awake."</p><p>"Doesn't matter if she is. Open, bought-and-paid-for."</p><p>"Pass her down, I've not had a turn."</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "core_strain", "operator": "gte", "value": 48}, {"type": "trait", "subject": "player", "trait_key": "core_strain", "operator": "lt", "value": 72}]})>>
<video src="./videos/sex/cell_sleep_faulting_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>They keep her surfacing now. Every time she starts to slip they haul her back onto her knees and use her hard, one fisting her hair down onto his cock till she gags and drools, another driving into her from behind, handprints coming up on her ass and a set of fingermarks banding her throat. Then they flip her and take her in the ass. The drain is inverted now, the thing that used to TAKE from a man only pouring INTO her. Bastien holds her jaw and makes her come on it because forcing it spikes the readout fastest, and the number jumps two, three, climbing in the dark while she can't tell sleep from being fucked.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Make her come. That's what moves the count, not the fucking. Force it. Watch the plate, not her.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Up it goes. Look at that. Passed round all night and still filling.</div></div><p>"She's shaking. Do it again, it likes it."</p><p>"Hold her mouth, she's trying to check out."</p><p>"Mark her up, no one's counting bruises."</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "core_strain", "operator": "gte", "value": 72}]})>>
<video src="./videos/sex/cell_sleep_failing_t5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><p>By the small hours her body's half-quitting under them. Legs gone loose, breath sawing, the sternum plate flickering its readout where it should hold steady. None of them slow down for it. The charge has stacked up so high with nowhere to drain that every load now lands as a wet flare of pain instead of anything else, and they force her over the edge anyway, again, the pleasure coming out the wrong way and hurting, the plate stuttering the number up past where the light stays on. She's limp between them, used front and back, drooled-on and slack, and Bastien just leans in close to read the flicker off her chest and not her face at all.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> It's browning out. Good — keep going. I want to see how high it climbs before the light won't hold.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/bastien.jpg" alt="Bastien" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Bastien</strong> Not her, idiot. The plate. Watch the plate. She's just the socket.</div></div><p>"Something's wrong with it. Look, it's flickering."</p><p>"Boss says keep going, so keep going."</p><p>"Still warm, still open. Who cares if it's breaking."</p>
<</if>>
<<set $game_state.current_canvas = "cell_sleep">>
<<set $game_state.current_node = "cell_sleep.base">>
<<script>>setup.markCanvasTriggered("cell_sleep");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("cell_sleep.base") === -1) { vn.push("cell_sleep.base"); }<</script>>
<<script>>advanceTime(540);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "energy", "add", 100.0, true, null);setup.applyAndNotifyTrait("player", null, "core_strain", "add", 12.0, true, null);setup.showEffectNotification();<</script>>
[[Wake up.->Location_captive_room]]<p>The locker at the foot of the bed holds everything the company has ever issued her and two things it hasn't. She stands in front of it with the door open and picks what the day needs her to look like.</p>
<<set $game_state.current_canvas = "activity_wren_change">>
<<set $game_state.current_node = "activity_wren_change.base">>
<<script>>setup.markCanvasTriggered("activity_wren_change");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_wren_change.base") === -1) { vn.push("activity_wren_change.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "clothing_item", "item_id": "cover_dockhand", "operator": "owned"}]})>>
<span @class="setup.isChoiceVisited('activity_wren_change:cc0') ? '' : 'unlocked-choice'">
<<link "Into the dock-work coveralls." "Canvas_activity_wren_change_Node_dock">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.addToWardrobe("cover_dockhand"); setup.equipItem("cover_dockhand");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_wren_change:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="She hasn't been issued anything to work a dock in. Whatever the job turns out to be, it comes with the clothes.">She hasn't been issued anything to work a dock in. Whatever the job turns out to be, it comes with the clothes.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "clothing_item", "item_id": "cover_analyst", "operator": "owned"}]})>>
<span @class="setup.isChoiceVisited('activity_wren_change:cc1') ? '' : 'unlocked-choice'">
<<link "Into the junior-analyst kit." "Canvas_activity_wren_change_Node_analyst">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.addToWardrobe("cover_analyst"); setup.equipItem("cover_analyst");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_wren_change:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Nothing in the locker would get her past a desk on a Vance floor. That kit comes from Mercer, when Mercer wants her on one.">Nothing in the locker would get her past a desk on a Vance floor. That kit comes from Mercer, when Mercer wants her on one.</span><br>
<</if>>
<<link "Back into company grays." "Canvas_activity_wren_change_Node_grays">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.addToWardrobe("company_grays"); setup.equipItem("company_grays");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Leave it." "Location_wren_room">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Heavy canvas, worn at the knees by somebody else first, and it smells of a shed. In the mirror there is a woman who lifts things for a living and no reason at all to look at her twice. That is the entire point of it.</p>
<<set $game_state.current_canvas = "activity_wren_change">>
<<set $game_state.current_node = "activity_wren_change.dock">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_wren_change.dock") === -1) { vn.push("activity_wren_change.dock"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Out.->Location_wren_room]]<p>Grey, cut close, a size too junior to be worth resenting. It is the same trick as the coveralls run the other way. Not a woman nobody looks at. A woman everybody has already decided they know.</p>
<<set $game_state.current_canvas = "activity_wren_change">>
<<set $game_state.current_node = "activity_wren_change.analyst">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_wren_change.analyst") === -1) { vn.push("activity_wren_change.analyst"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Out.->Location_wren_room]]<p>The company line goes back on and sits the way it always sits. That is correctly. She has never once chosen these and has never once been out of them long enough to notice she wasn't.</p>
<<set $game_state.current_canvas = "activity_wren_change">>
<<set $game_state.current_node = "activity_wren_change.grays">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_wren_change.grays") === -1) { vn.push("activity_wren_change.grays"); }<</script>>
<<script>>advanceTime(15);<</script>>
[[Out.->Location_wren_room]]<p>She strips and stands under the water until whatever the work left on her is gone. Sweat, a client's hands, the smell of the docks. The company keeps her maintained; this part she does for herself, the one washing that is hers alone. She comes out clean, and for a minute, almost new.</p>
<<set $game_state.current_canvas = "activity_wash">>
<<set $game_state.current_node = "activity_wash.base">>
<<script>>setup.markCanvasTriggered("activity_wash");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_wash.base") === -1) { vn.push("activity_wash.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "hygiene", "add", 100.0, true, null);setup.showEffectNotification();<</script>>
[[Dry off. Dressed.->Location_wren_room]]<img src="./videos/locations/underworld_market.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Past the blades and the field-kit there are three tables nobody stops at, stacked with the insides of things: salvage boards, drawer after drawer of small dead components sorted by nothing. The man behind the tables keeps his head down until she says what she is after.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "part_spec", "operator": "lt", "value": 1}]})>>
<p>A talkback. He doesn't blink at the word. He turns a drawer round and lets her pick out of forty of them, none of which he can tell apart either.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "part_spec", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "part_spec", "operator": "lt", "value": 2}]})>>
<p>A sweep head. That gets a second look. Sweeps come off signal boards, and nobody buys one to fix a signal board. He puts a flat grey wafer on the cloth and names a price unasked.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "part_spec", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "part_spec", "operator": "lt", "value": 3}]})>>
<p>An isolator. He tells her it's dead stock and it's sat on that shelf two years, which she already knew, because the man who sent her said the same sentence. It is heavier than it looks.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "part_spec", "operator": "gte", "value": 3}]})>>
<p>A stacked talkback. He goes into the back for this one. When he comes out he sets it down and looks at her for the first time in four visits, and decides against asking.</p>
<</if>>
<<set $game_state.current_canvas = "activity_buy_part">>
<<set $game_state.current_node = "activity_buy_part.base">>
<<script>>setup.markCanvasTriggered("activity_buy_part");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_part.base") === -1) { vn.push("activity_buy_part.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "spec_pending", "operator": "lt", "value": 1}]})>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 25}])>>
<span @class="setup.isChoiceVisited('activity_buy_part:cc0') ? '' : 'unlocked-choice'">
<<link "Buy a part. (25 coin.)" "Canvas_activity_buy_part_Node_buy">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "part_held", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -25, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_buy_part:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Buy a part. (25 coin.)">Buy a part. (25 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 25}])>>)</span><br>
<</if>>
<<else>>
<span class="locked-choice" title="The last one burned out in her and she has not been back to the berth since. Buying another before Kess has said what went wrong is how the first twenty-five went — he asks what it did, and then he says what to get.">The last one burned out in her and she has not been back to the berth since. Buying another before Kess has said what went wrong is how the first twenty-five went — he asks what it did, and then he says what to get.</span><br>
<</if>>
<<link "Leave the tables." "Location_underworld_market">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The man behind the drawers takes the coin with his eyes down and lets the question go. That is the only service on offer down here and the only one worth coin. It goes in her coat with the other thing she is not carrying openly.</p>
<<set $game_state.current_canvas = "activity_buy_part">>
<<set $game_state.current_node = "activity_buy_part.buy">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_part.buy") === -1) { vn.push("activity_buy_part.buy"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Take it to him.->Location_underworld_market]]<img src="./videos/locations/underworld_market.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Two tables past the blades a man does bonded freight. Grey courier cases stacked to his shoulder, each with a reader plate let into the lid. Nothing down here moves without a hand on it at both ends.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline"><<print $player.name>></strong> It keeps the hand that opens it.</div></div><p>That's the whole product, he says. Anyone can carry a box. The case is how you prove who took delivery, and it holds that a year.</p>
<<set $game_state.current_canvas = "activity_buy_case">>
<<set $game_state.current_node = "activity_buy_case.base">>
<<script>>setup.markCanvasTriggered("activity_buy_case");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_case.base") === -1) { vn.push("activity_buy_case.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 25}])>>
<<link "Have him bond a bottle into one. (25 coin.)" "Canvas_activity_buy_case_Node_buy">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "case_held", "set", 1.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -25, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Have him bond a bottle into one. (25 coin.)">Have him bond a bottle into one. (25 coin.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 25}])>>)</span><br>
<</if>>
<<link "Leave the table." "Location_underworld_market">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>He seats a bottle in the foam, drops the lid, and the reader plate goes dull and waiting. It is a good bottle. It is a better box, and only one of the two is going back to the Reach with her.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> He will open it in front of her. He will not be able to help it, and he will be pleased, and the empty will be sitting on the floor when she leaves.</div></div>
<<set $game_state.current_canvas = "activity_buy_case">>
<<set $game_state.current_node = "activity_buy_case.buy">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_buy_case.buy") === -1) { vn.push("activity_buy_case.buy"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Pocket it.->Location_underworld_market]]<img src="./videos/locations/underworld_market.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Coin moves here for everything the Spire pretends doesn't exist. Blades and field-gear on the near tables; further back, behind chain, the part she doesn't look at directly. She has coin now. She can leave with an edge.</p>
<<set $game_state.current_canvas = "underworld_market_shop">>
<<set $game_state.current_node = "underworld_market_shop.base">>
<<script>>setup.markCanvasTriggered("underworld_market_shop");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_market_shop.base") === -1) { vn.push("underworld_market_shop.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 40}])>>
<<link "Buy a weapon — something with an edge." "Canvas_underworld_market_shop_Node_weapon">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -40, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Buy a weapon — something with an edge.">Buy a weapon — something with an edge. (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 40}])>>)</span><br>
<</if>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 30}])>>
<<link "Buy infiltration gear." "Canvas_underworld_market_shop_Node_gear">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -30, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Buy infiltration gear.">Buy infiltration gear. (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 30}])>>)</span><br>
<</if>>
<<link "Walk the pens." "Canvas_underworld_market_shop_Node_pens">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Leave the stalls." "Location_underworld_market">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She buys a blade the way a soldier does. By balance, not by looks. And a thing to hide it in. Her hands are deadlier leaving than they were coming in. Coin well spent.</p>
<<set $game_state.current_canvas = "underworld_market_shop">>
<<set $game_state.current_node = "underworld_market_shop.weapon">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_market_shop.weapon") === -1) { vn.push("underworld_market_shop.weapon"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Stow it.->Location_underworld_market]]<p>Soft soles, a light that isn't a light, a tool roll that opens what's meant to stay shut. The kind of kit that turns a careful woman invisible. Coin well spent.</p>
<<set $game_state.current_canvas = "underworld_market_shop">>
<<set $game_state.current_node = "underworld_market_shop.gear">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_market_shop.gear") === -1) { vn.push("underworld_market_shop.gear"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Pack it away.->Location_underworld_market]]<p>Behind the chain they keep people the way the market keeps anything. By weight and condition, tagged, waiting on a buyer. She walks the line because she makes herself walk it. Most are just people, stolen and sold. But one of them, a girl too still, too even, watches her back with eyes that don't track quite right. Something in Wren's chest does a thing it has no name for, a recognition she shuts off before it finishes. She's looked at her own reflection in a cage. She shuts it down and walks out.</p>
<<set $game_state.current_canvas = "underworld_market_shop">>
<<set $game_state.current_node = "underworld_market_shop.pens">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_market_shop.pens") === -1) { vn.push("underworld_market_shop.pens"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Don't look again.->Location_underworld_market]]<p>The ring is a pit of packed dirt under a single bulb, the crowd three deep around it laying coin on the next body to fall. The matchmaker looks her up and down, unimpressed, and asks what she thinks she can take. Down here her fists pay the same as the rest of her.</p>
<<set $game_state.current_canvas = "underworld_pit_fight">>
<<set $game_state.current_node = "underworld_pit_fight.base">>
<<script>>setup.markCanvasTriggered("underworld_pit_fight");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_pit_fight.base") === -1) { vn.push("underworld_pit_fight.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 10}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('underworld_pit_fight:cc0') ? '' : 'unlocked-choice'">
<<link "Take a low bout." "Canvas_underworld_pit_fight_Node_win_low">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 8.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("underworld_pit_fight:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Take a low bout.">Take a low bout. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 30}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 20}])>>
<span @class="setup.isChoiceVisited('underworld_pit_fight:cc1') ? '' : 'unlocked-choice'">
<<link "Take a hard bout." "Canvas_underworld_pit_fight_Node_win_hard">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", 20.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -20, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("underworld_pit_fight:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Take a hard bout.">Take a hard bout. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 20}])>>)</span><br>
<</if>>
<</if>>
<<link "Just watch tonight." "Location_underworld_pit">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>They put a brawler in with her, slow and heavy. She lets him swing, reads the half-beat, and ends it with the kind of economy the crowd doesn't cheer because it scared them. The matchmaker pays out without meeting her eyes.</p>
<<set $game_state.current_canvas = "underworld_pit_fight">>
<<set $game_state.current_node = "underworld_pit_fight.win_low">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_pit_fight.win_low") === -1) { vn.push("underworld_pit_fight.win_low"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Take the purse.->Location_underworld_pit]]<p>This one's real. Fast, trained, in it to hurt her. For a few seconds it's almost a fight. Then the thing they built her to be takes over, and what's left on the dirt isn't getting up. The crowd goes quiet. The purse is heavy. Someone in the dark is watching her now.</p>
<<set $game_state.current_canvas = "underworld_pit_fight">>
<<set $game_state.current_node = "underworld_pit_fight.win_hard">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_pit_fight.win_hard") === -1) { vn.push("underworld_pit_fight.win_hard"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Take the purse.->Location_underworld_pit]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 0}]})>>
<p>He holds her head still and finishes in her mouth; she takes it, swallows because the trade expects it, and sits back on her heels. He's already reaching for his drink.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_brothel_finish_facial_t5"] to ($game_state.media_cycle["sex_brothel_finish_facial_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_brothel_finish_facial_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_brothel_finish_facial_t5"]>><<if _mc is 0>><video src="./videos/sex/brothel_finish_facial_t5/c6d8642c4ce.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/brothel_finish_facial_t5/c357c6f5e3b.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/brothel_finish_facial_t5/c11885f84f7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/brothel_finish_facial_t5/cf44f170f7a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 1}]})>>
<p>He finishes inside her with a grunt, holds, then pulls out. His cum slides down the inside of her thigh. She waits the polite beat and lifts off, and counts the coin into her palm.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_brothel_finish_inside_t5"] to ($game_state.media_cycle["sex_brothel_finish_inside_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_brothel_finish_inside_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_brothel_finish_inside_t5"]>><<if _mc is 0>><video src="./videos/sex/brothel_finish_inside_t5/c337e9650c8.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/brothel_finish_inside_t5/cb957733146.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/brothel_finish_inside_t5/cc9de118c53.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/brothel_finish_inside_t5/cf82c9b4a8d.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "sex_finisher_type", "operator": "eq", "value": 2}]})>>
<p>He finishes in her ass and stays a moment, breathing, then steps back. His weight and his cum and then nothing. The same nothing as every man down here. She straightens. The next one's already on the stairs.</p><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_brothel_finish_ass_t5"] to ($game_state.media_cycle["sex_brothel_finish_ass_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_brothel_finish_ass_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_brothel_finish_ass_t5"]>><<if _mc is 0>><video src="./videos/sex/brothel_finish_ass_t5/c0e3bde7dad.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/brothel_finish_ass_t5/c4ce7281131.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/brothel_finish_ass_t5/c24ff40fdee.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/brothel_finish_ass_t5/cfc8b2c7e60.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>>
<</if>>
<<set $game_state.current_canvas = "underworld_brothel_finisher">>
<<set $game_state.current_node = "underworld_brothel_finisher.climax">>
<<script>>setup.markCanvasTriggered("underworld_brothel_finisher");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_brothel_finisher.climax") === -1) { vn.push("underworld_brothel_finisher.climax"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "coin", "add", 30.0, false, null);setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);setup.showEffectNotification();<</script>>
[[Clean up. Collect.->Location_underworld_brothel]]<p>The madam points her at a door. The man inside keeps his eyes on his drink until she's undressed. Then he looks her over the way men look over rented things, deciding where to start. No name, no preamble. He paid for the hour and means to use it.</p>
<<set $game_state.current_canvas = "underworld_brothel_loop">>
<<set $game_state.current_node = "underworld_brothel_loop.intro">>
<<script>>setup.markCanvasTriggered("underworld_brothel_loop");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_brothel_loop.intro") === -1) { vn.push("underworld_brothel_loop.intro"); }<</script>>
<<nobr>>
<<link "Down on your knees." "Canvas_underworld_brothel_loop_Node_base_oral">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_brothel_oral_t5"] to ($game_state.media_cycle["sex_brothel_oral_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_brothel_oral_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_brothel_oral_t5"]>><<if _mc is 0>><video src="./videos/sex/brothel_oral_t5/c149abc39d7.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/brothel_oral_t5/ca8e8acc6b0.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/brothel_oral_t5/cd99a4b7363.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/brothel_oral_t5/cfd198e1bff.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>On her knees between his, she takes his cock in her mouth and works it the way the trade taught her. Steady, practiced, her eyes somewhere past his hip. He fists a hand in her hair and sets the pace. She lets him. None of it reaches her.</p>
<<set $game_state.current_canvas = "underworld_brothel_loop">>
<<set $game_state.current_node = "underworld_brothel_loop.base_oral">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_brothel_loop.base_oral") === -1) { vn.push("underworld_brothel_loop.base_oral"); }<</script>>
<<nobr>>
<<link "Keep sucking him." "Canvas_underworld_brothel_loop_Node_base_oral">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Climb on and ride him." "Canvas_underworld_brothel_loop_Node_base_vaginal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Turn around and give him your ass." "Canvas_underworld_brothel_loop_Node_base_anal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('underworld_brothel_loop:cc0') ? '' : 'unlocked-choice'">
<<link "Let him finish in your mouth." "Canvas_underworld_brothel_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("underworld_brothel_loop:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_brothel_vaginal_t5"] to ($game_state.media_cycle["sex_brothel_vaginal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_brothel_vaginal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_brothel_vaginal_t5"]>><<if _mc is 0>><video src="./videos/sex/brothel_vaginal_t5/c450060d15a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/brothel_vaginal_t5/cdb6120d3c5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/brothel_vaginal_t5/ceac1aa782c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/brothel_vaginal_t5/cf64e33c40c.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She climbs on and takes his cock briskly, sinks down and rides, hips keeping a rhythm that belongs to the job. He paws at her tits and fucks up into her; she gives him the small sounds the trade expects and feels none of them.</p>
<<set $game_state.current_canvas = "underworld_brothel_loop">>
<<set $game_state.current_node = "underworld_brothel_loop.base_vaginal">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_brothel_loop.base_vaginal") === -1) { vn.push("underworld_brothel_loop.base_vaginal"); }<</script>>
<<nobr>>
<<link "Keep riding him." "Canvas_underworld_brothel_loop_Node_base_vaginal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back down on your knees." "Canvas_underworld_brothel_loop_Node_base_oral">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Let him have your ass." "Canvas_underworld_brothel_loop_Node_base_anal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}]})>>
<span @class="setup.isChoiceVisited('underworld_brothel_loop:cc1') ? '' : 'unlocked-choice'">
<<link "Let him finish inside you." "Canvas_underworld_brothel_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("underworld_brothel_loop:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_brothel_anal_t5"] to ($game_state.media_cycle["sex_brothel_anal_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_brothel_anal_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_brothel_anal_t5"]>><<if _mc is 0>><video src="./videos/sex/brothel_anal_t5/c0e943a0442.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/brothel_anal_t5/c7e7b540eff.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/brothel_anal_t5/cd22d1b3c41.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/brothel_anal_t5/ce556b0edee.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>Bent over the edge of the bed, she takes him in the ass in long flat strokes, both his hands clamped on her hips. Just more friction down a body that gives nothing back. She braces and waits it out, counting somewhere behind her own face what the hour's worth.</p>
<<set $game_state.current_canvas = "underworld_brothel_loop">>
<<set $game_state.current_node = "underworld_brothel_loop.base_anal">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_brothel_loop.base_anal") === -1) { vn.push("underworld_brothel_loop.base_anal"); }<</script>>
<<nobr>>
<<link "Take it." "Canvas_underworld_brothel_loop_Node_base_anal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "add", (Math.floor(Math.random() * 7) + 8), false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Back onto his cock." "Canvas_underworld_brothel_loop_Node_base_vaginal">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "loop_npc_pleasure", "operator": "gte", "value": 50}, {"type": "trait", "subject": "player", "trait_key": "anal_active", "operator": "gte", "value": 1}]})>>
<span @class="setup.isChoiceVisited('underworld_brothel_loop:cc2') ? '' : 'unlocked-choice'">
<<link "Let him finish in your ass." "Canvas_underworld_brothel_finisher_Node_climax">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("underworld_brothel_loop:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>The madam counts her with one look and tips her head at the rooms. No contract, no company, no Mercer signing her out. Just a door, a client, and coin at the end that goes in her pocket and nowhere else. The thing she's built for, sold for once, on her own account.</p>
<<set $game_state.current_canvas = "underworld_brothel_work">>
<<set $game_state.current_node = "underworld_brothel_work.base">>
<<script>>setup.markCanvasTriggered("underworld_brothel_work");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_brothel_work.base") === -1) { vn.push("underworld_brothel_work.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<<link "Take a client." "Canvas_underworld_brothel_loop_Node_intro">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "loop_npc_pleasure", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_stage", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_finisher_type", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "anal_active", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "sex_entry_origin", "set", 0.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Take a client.">Take a client. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<<link "Not tonight." "Location_underworld_brothel">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><img src="./videos/locations/underworld_strip.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She walks back up the strip. The house, the pit, the market closing behind her, and past them the dark where the real city keeps its teeth. Down here nobody was looking for her. It's the closest thing to free she's felt.</p>
<<set $game_state.current_canvas = "underworld_strip_hub">>
<<set $game_state.current_node = "underworld_strip_hub.base">>
<<script>>setup.markCanvasTriggered("underworld_strip_hub");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_strip_hub.base") === -1) { vn.push("underworld_strip_hub.base"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "energy", "add", -10.0, true, null);setup.showEffectNotification();<</script>>
[[Out to the gate.->Location_underworld_gate]]<img src="./videos/locations/underworld_gate.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The man at the door asks for coin, not a name. He looks her over the way a turnstile would and holds out a hand. "Coin," he says. "Or you're not my problem." Behind him the stairs go down into red light and noise. There's more than one way through a man like this. The coin he wants is underworld scrip, not company credits. Earned down here, spent down here, worth nothing up top.</p>
<<set $game_state.current_canvas = "underworld_gate_check">>
<<set $game_state.current_node = "underworld_gate_check.base">>
<<script>>setup.markCanvasTriggered("underworld_gate_check");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_gate_check.base") === -1) { vn.push("underworld_gate_check.base"); }<</script>>
<<nobr>>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 5}])>>
<<link "Pay the toll." "Location_underworld_strip">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -5, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="Pay the toll.">Pay the toll. (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 5}])>>)</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 15}]})>>
<span @class="setup.isChoiceVisited('underworld_gate_check:cc0') ? '' : 'unlocked-choice'">
<<link "Force past him." "Location_underworld_strip">><<script>>setup.markChoiceVisited("underworld_gate_check:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})>>
<<if setup.checkCostsAffordable([{"trait": "arousal_charge", "value": 1}])>>
<span @class="setup.isChoiceVisited('underworld_gate_check:cc1') ? '' : 'unlocked-choice'">
<<link "Put the weapon on him." "Canvas_underworld_gate_check_Node_weapon_scene">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "add", -1, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("underworld_gate_check:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Put the weapon on him.">Put the weapon on him. (<<= setup.getCostBlockedMessage([{"trait": "arousal_charge", "value": 1}])>>)</span><br>
<</if>>
<</if>>
<<link "Turn back." "Location_the_waterfront">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_arousal_weapon_use_t5"] to ($game_state.media_cycle["sex_arousal_weapon_use_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_arousal_weapon_use_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_arousal_weapon_use_t5"]>><<if _mc is 0>><video src="./videos/sex/arousal_weapon_use_t5/c80a1baf7f5.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/arousal_weapon_use_t5/c759429da3f.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/arousal_weapon_use_t5/c44022617b2.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/arousal_weapon_use_t5/cf66883e910.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She thumbs the emitter and the doorman's whole face changes. The bored menace gone, breath short, the hand that wanted coin wanting something else now. She walks him back into the shadow of the stair, gets his cock out, and rides him against the wall in quick flat strokes, fast and clinical, giving him nothing but the friction. He spills into her with his eyes rolling white and sags down the bricks, under. He'll wake on the steps in an hour with no memory, and never know she walked past him. The stairs are open.</p>
<<set $game_state.current_canvas = "underworld_gate_check">>
<<set $game_state.current_node = "underworld_gate_check.weapon_scene">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("underworld_gate_check.weapon_scene") === -1) { vn.push("underworld_gate_check.weapon_scene"); }<</script>>
<<script>>advanceTime(60);<</script>>
[[Down into the strip.->Location_underworld_strip]]<img src="./videos/locations/kess_berth.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}]})>>
<p>The emitter lies on Kess's bench between two things he is not working on. One core, one weapon. It feeds the drain inside her or the thing in her hand, never both at once. Right now it's the drain.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<p>The emitter's live in her coat, the drain inside her gone quiet behind it. One core, one weapon. Right now it's the emitter, and the gate is the only place down here that cares.</p>
<</if>>
<<set $game_state.current_canvas = "activity_swap_weapon_berth">>
<<set $game_state.current_node = "activity_swap_weapon_berth.base">>
<<script>>setup.markCanvasTriggered("activity_swap_weapon_berth");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_swap_weapon_berth.base") === -1) { vn.push("activity_swap_weapon_berth.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}]})>>
<span @class="setup.isChoiceVisited('activity_swap_weapon_berth:cc0') ? '' : 'unlocked-choice'">
<<link "Run the emitter instead." "Location_kess_berth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_swap_weapon_berth:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('activity_swap_weapon_berth:cc1') ? '' : 'unlocked-choice'">
<<link "Go back to the drain." "Location_kess_berth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_swap_weapon_berth:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave it." "Location_the_cot">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}]})>>
<p>The emitter sits charged on the bench. One core, one weapon. It feeds the drain inside her or the thing in her hand, never both at once. Right now it's the drain.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<p>The emitter's live in her hand, the drain inside her gone quiet behind it. One core, one weapon. Right now it's the emitter.</p>
<</if>>
<<set $game_state.current_canvas = "activity_swap_weapon">>
<<set $game_state.current_node = "activity_swap_weapon.base">>
<<script>>setup.markCanvasTriggered("activity_swap_weapon");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_swap_weapon.base") === -1) { vn.push("activity_swap_weapon.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 1}]})>>
<span @class="setup.isChoiceVisited('activity_swap_weapon:cc0') ? '' : 'unlocked-choice'">
<<link "Run the emitter instead." "Location_wren_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_swap_weapon:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}]})>>
<span @class="setup.isChoiceVisited('activity_swap_weapon:cc1') ? '' : 'unlocked-choice'">
<<link "Go back to the drain." "Location_wren_room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "equipped_weapon", "set", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_swap_weapon:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<link "Leave it." "Location_wren_room">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The emitter sits on her bench, casing off, guts exposed. She knows the architecture of it the way she knows her own. Because it is her own, scaled down to a handheld. Heat-warp on the field coils, a cracked driver. Slow work, and hers alone.</p>
<<set $game_state.current_canvas = "activity_repair_weapon">>
<<set $game_state.current_node = "activity_repair_weapon.base">>
<<script>>setup.markCanvasTriggered("activity_repair_weapon");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_repair_weapon.base") === -1) { vn.push("activity_repair_weapon.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "lt", "value": 2}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_repair_weapon:cc0') ? '' : 'unlocked-choice'">
<<link "Work on it." "Canvas_activity_repair_weapon_Node_progress">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "weapon_repair", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_repair_weapon:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work on it.">Work on it. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "lt", "value": 3}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_repair_weapon:cc1') ? '' : 'unlocked-choice'">
<<link "Finish it." "Canvas_activity_repair_weapon_Node_done">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "weapon_repair", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "arousal_weapon_ready", "set");<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_repair_weapon:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Finish it.">Finish it. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<link "Leave it for now." "Location_wren_room">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "lt", "value": 2}]})>>
<p>She straightens the field coils, one pass, and tests the draw. Dead still. Cleaner dead than it was. More to do.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "weapon_repair", "operator": "gte", "value": 2}]})>>
<p>Driver reseated, coils true. It draws a charge now and holds it. A flicker of the field crossing her own skin, the faint unwanted warmth of it. Almost. One more pass and it fires.</p>
<</if>>
<<set $game_state.current_canvas = "activity_repair_weapon">>
<<set $game_state.current_node = "activity_repair_weapon.progress">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_repair_weapon.progress") === -1) { vn.push("activity_repair_weapon.progress"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Set it down.->Location_wren_room]]<p>Last pass. She powers it and the field comes up clean, a low hum she feels in her teeth. She tests it on herself a half-second too long and gets a heat low in her belly she didn't ask for. She shuts it off fast. It works. A second weapon now, hers, that the company never issued and doesn't know she has. A way past any man who outmatches her.</p>
<<set $game_state.current_canvas = "activity_repair_weapon">>
<<set $game_state.current_node = "activity_repair_weapon.done">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_repair_weapon.done") === -1) { vn.push("activity_repair_weapon.done"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Stow it.->Location_wren_room]]<p>The strongroom is what he saved. Two personnel files, a man each. His own people, the two who moved the materials. Both stamped CLOSED. Under each, a death notice, and under that, more notices: wives, children, the whole line, the dates all the same night. Renner didn't just fire them. He erased them. And paperclipped to the back, the thing he's really hiding: where the two men came from before Vance. The same name twice, a place down in the city the maps leave blank. The underworld. That's the thread Cain followed back. That's where it goes.</p><p>Standing in it, something turns over in her. Not a thought. A feeling, brief and uninvited: she has stood in a room like this before, on the other side of the file. Then it's gone, filed under nothing.</p>
<<set $game_state.current_canvas = "yard_find_3">>
<<set $game_state.current_node = "yard_find_3.base">>
<<script>>setup.markCanvasTriggered("yard_find_3");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_find_3.base") === -1) { vn.push("yard_find_3.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "found_dead_men", "set");<</script>>
[[Take what matters. Go.->Location_renner_burned_yard]]<img src="./videos/activities/arousal_weapon.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>In a melted equipment locker, half-slagged but whole at the core, is a device she knows in her hands before she knows in her head. The same build as the thing inside her, the one that makes a body want against its own sense. A field emitter. Renner had one off the line and never fired it. Heat-warped, dead. But the core is sound. She pockets it. Fixed, it's a way past any man who'd otherwise put her down.</p>
<<set $game_state.current_canvas = "yard_find_2">>
<<set $game_state.current_node = "yard_find_2.base">>
<<script>>setup.markCanvasTriggered("yard_find_2");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_find_2.base") === -1) { vn.push("yard_find_2.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "has_arousal_weapon", "set");<</script>>
[[Take it. Get out clean.->Location_renner_burned_yard]]<p>Inside the outer line she finds the shape of it under the burn: not just a storage yard. Loading bays built for things heavier than crates, restraint points set into a slab, a billing wall scorched but legible. Shipments logged out to the same Vance facility she's already walked the ashes of. Renner moved more than equipment through here. He just never asked what for.</p>
<<set $game_state.current_canvas = "yard_find_1">>
<<set $game_state.current_node = "yard_find_1.base">>
<<script>>setup.markCanvasTriggered("yard_find_1");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_find_1.base") === -1) { vn.push("yard_find_1.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "yard_clue_seen", "set");<</script>>
[[Log it. Keep moving.->Location_renner_burned_yard]]<img src="./videos/locations/renner_burned_yard.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 1}]})>>
<p>The fence is down on the water side. Past it the yard is black glass and bent steel. A guard with a torch walks the line where the gate used to be. Getting in means getting past him.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 3}]})>>
<p>She's inside the outer line now. Deeper in there are more lights and more men. Renner guards a dead yard this hard for a reason. Whatever's worth guarding is further back.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "gte", "value": 3}]})>>
<p>She's been all the way to the back of it. She has put her hands on everything in the yard.</p>
<</if>>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.base">>
<<script>>setup.markCanvasTriggered("yard_crawl");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.base") === -1) { vn.push("yard_crawl.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 1}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('yard_crawl:cc0') ? '' : 'unlocked-choice'">
<<link "Push in past the gate." "Canvas_yard_crawl_Node_guard1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Push in past the gate.">Push in past the gate. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 2}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('yard_crawl:cc1') ? '' : 'unlocked-choice'">
<<link "Work deeper in." "Canvas_yard_crawl_Node_guard2">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Work deeper in.">Work deeper in. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 3}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('yard_crawl:cc2') ? '' : 'unlocked-choice'">
<<link "Push to the back of it." "Canvas_yard_crawl_Node_guard3">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Push to the back of it.">Push to the back of it. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<link "Slip back out." "Location_the_waterfront">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>One man, one torch, bored and slow. The easy one, the test before the real ones. He hasn't seen her yet.</p>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.guard1">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.guard1") === -1) { vn.push("yard_crawl.guard1"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 10}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc3') ? '' : 'unlocked-choice'">
<<link "Slip past him, unseen." "Canvas_yard_crawl_Node_deeper">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 10}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc4') ? '' : 'unlocked-choice'">
<<link "Take him down." "Canvas_yard_crawl_Node_deeper">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc5') ? '' : 'unlocked-choice'">
<<link "Use the weapon on him." "Canvas_yard_crawl_Node_weapon_scene">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "add", -1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc6') ? '' : 'unlocked-choice'">
<<link "He's on you — break and run." "Canvas_yard_crawl_Node_flee">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc6");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 10}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 10}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}]})))>>
<<script>>
try {
window._engineNoExitsDiag_yard_crawl = [{"text": "Slip past him, unseen.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 10}]}}, {"text": "Take him down.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 10}]}}, {"text": "Use the weapon on him.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]}}, {"text": "He's on you \u2014 break and run.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 10}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "yard_crawl",
choices: window._engineNoExitsDiag_yard_crawl,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_yard_crawl>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas yard_crawl</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Location_renner_burned_yard]]
<</if>>
<</nobr>><p>Two of them here, awake and armed, working a pattern between the racks. Past the easy line. These ones would hurt her if she let them.</p>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.guard2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.guard2") === -1) { vn.push("yard_crawl.guard2"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 25}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc7') ? '' : 'unlocked-choice'">
<<link "Slip past them, unseen." "Canvas_yard_crawl_Node_deeper">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc7");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 25}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc8') ? '' : 'unlocked-choice'">
<<link "Take them down." "Canvas_yard_crawl_Node_deeper">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc8");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc9') ? '' : 'unlocked-choice'">
<<link "Use the weapon on them." "Canvas_yard_crawl_Node_weapon_scene">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "add", -1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc9");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc10') ? '' : 'unlocked-choice'">
<<link "Too many — break and run." "Canvas_yard_crawl_Node_flee">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc10");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 25}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 25}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}]})))>>
<<script>>
try {
window._engineNoExitsDiag_yard_crawl = [{"text": "Slip past them, unseen.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 25}]}}, {"text": "Take them down.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 25}]}}, {"text": "Use the weapon on them.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]}}, {"text": "Too many \u2014 break and run.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "yard_crawl",
choices: window._engineNoExitsDiag_yard_crawl,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_yard_crawl>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas yard_crawl</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Location_renner_burned_yard]]
<</if>>
<</nobr>><p>The heaviest watch is here, at the back. A knot of his best men around a strongroom the fire missed. Whatever Renner's keeping, it's behind them.</p>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.guard3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.guard3") === -1) { vn.push("yard_crawl.guard3"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 40}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc11') ? '' : 'unlocked-choice'">
<<link "Ghost straight through them." "Canvas_yard_crawl_Node_deeper">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc11");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 40}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc12') ? '' : 'unlocked-choice'">
<<link "Cut through them." "Canvas_yard_crawl_Node_deeper">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc12");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc13') ? '' : 'unlocked-choice'">
<<link "Use the weapon on them." "Canvas_yard_crawl_Node_weapon_scene">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "yard_depth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "add", -1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "hygiene", "add", -30.0, true, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc13");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}]})>>
<span @class="setup.isChoiceVisited('yard_crawl:cc14') ? '' : 'unlocked-choice'">
<<link "Not yet — break and run." "Canvas_yard_crawl_Node_flee">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "yard_caught_once", "set");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("yard_crawl:cc14");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 40}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 40}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}]})))>>
<<script>>
try {
window._engineNoExitsDiag_yard_crawl = [{"text": "Ghost straight through them.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 40}]}}, {"text": "Cut through them.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 40}]}}, {"text": "Use the weapon on them.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "equipped_weapon", "operator": "eq", "value": 2}, {"type": "flag", "subject": "player", "flag_key": "arousal_weapon_ready", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "arousal_charge", "operator": "gte", "value": 1}, {"type": "trait", "subject": "player", "trait_key": "emitter_broken", "operator": "lt", "value": 1}]}}, {"text": "Not yet \u2014 break and run.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 40}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "yard_crawl",
choices: window._engineNoExitsDiag_yard_crawl,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_yard_crawl>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas yard_crawl</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Location_renner_burned_yard]]
<</if>>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 2}]})>>
<p>She's through the gate and into the outer yard, the guard behind her none the wiser or none the able. The dark swallows her.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "gte", "value": 2}, {"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "lt", "value": 3}]})>>
<p>Deeper now, in among the racks where the lights are. Past the men who'd have stopped her. She keeps to the shadow and goes on.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "yard_depth", "operator": "gte", "value": 3}]})>>
<p>The back of the yard, the strongroom, the thing they were all standing around. She's in.</p>
<</if>>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.deeper">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.deeper") === -1) { vn.push("yard_crawl.deeper"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[See what's here.->Location_renner_burned_yard]]<<if ndef $game_state.media_cycle>><<set $game_state.media_cycle to {}>><</if>><<set $game_state.media_cycle["sex_yard_emitter_fire_t5"] to ($game_state.media_cycle["sex_yard_emitter_fire_t5"] === undefined ? 0 : ($game_state.media_cycle["sex_yard_emitter_fire_t5"] + 1) % 4)>><<set _mc to $game_state.media_cycle["sex_yard_emitter_fire_t5"]>><<if _mc is 0>><video src="./videos/sex/yard_emitter_fire_t5/c0aafd22138.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 1>><video src="./videos/sex/yard_emitter_fire_t5/c2e25cd412a.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<elseif _mc is 2>><video src="./videos/sex/yard_emitter_fire_t5/c53ec986e91.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><<else>><video src="./videos/sex/yard_emitter_fire_t5/incumbent.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video><</if>><p>She thumbs the emitter and the field rolls out ahead of her. Whoever's in reach goes stupid with it inside a breath. Pupils blown, breath ragged, the gun forgotten in a slack hand. She picks the nearest, drags his cock out of his fatigues, and sinks down onto it against the crates, riding him in hard flat strokes while the others sway on their feet. There's nothing in it on her side. Just leverage. She works him until he spills into her and drops boneless and out. The rest fold a beat later. By the time any of them surface she's gone, deeper in, his cum drying on her thigh and nothing in her face at all.</p>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.weapon_scene">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.weapon_scene") === -1) { vn.push("yard_crawl.weapon_scene"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Step over them. On.->Location_renner_burned_yard]]<p>It goes against her. Too many, or too sharp, or her own body too slow. She breaks for the downed fence and is over the water side before the torches swing round. Nothing gained tonight. She walks it off.</p>
<<set $game_state.current_canvas = "yard_crawl">>
<<set $game_state.current_node = "yard_crawl.flee">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("yard_crawl.flee") === -1) { vn.push("yard_crawl.flee"); }<</script>>
<<script>>advanceTime(60);<</script>>
[[Get clear.->Location_the_waterfront]]<img src="./videos/locations/facility_ruins.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The facility is a black skeleton against the dock lights. Scorched frame, melted racks, the smell of old smoke that never washed out. She walks it slowly, cataloguing: where the containment was, where the fire started, what the dead machines used to do. None of it matches the briefing. All of it was built to hold things that could feel. Someone came through and let them out before he burned it down. The dread-place. The first one.</p>
<<set $game_state.current_canvas = "inv_facility_explore">>
<<set $game_state.current_node = "inv_facility_explore.base">>
<<script>>setup.markCanvasTriggered("inv_facility_explore");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("inv_facility_explore.base") === -1) { vn.push("inv_facility_explore.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Done here.->Location_facility_ruins]]<p>The floor's empty, the door shut. No one watches an asset in its own quarters. She uses the hour the way the company never told her to. Drilling the body they built, sharpening it past the spec on her file. It's the one thing here that's only hers.</p>
<<set $game_state.current_canvas = "activity_train">>
<<set $game_state.current_node = "activity_train.base">>
<<script>>setup.markCanvasTriggered("activity_train");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_train.base") === -1) { vn.push("activity_train.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "lt", "value": 30}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train:cc0') ? '' : 'unlocked-choice'">
<<link "Combat drill." "Canvas_activity_train_Node_combat">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Combat drill.">Combat drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 30}, {"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "lt", "value": 50}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train:cc1') ? '' : 'unlocked-choice'">
<<link "Combat drill." "Canvas_activity_train_Node_combat">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "fighting", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Combat drill.">Combat drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "yard_caught_once", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 30}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train:cc2') ? '' : 'unlocked-choice'">
<<link "Stealth drill." "Canvas_activity_train_Node_stealth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Stealth drill.">Stealth drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "yard_caught_once", "operator": "is_true"}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 30}, {"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 50}]})>>
<<if setup.checkCostsAffordable([{"trait": "energy", "value": 15}])>>
<span @class="setup.isChoiceVisited('activity_train:cc3') ? '' : 'unlocked-choice'">
<<link "Stealth drill." "Canvas_activity_train_Node_stealth">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "stealth", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", -15, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>setup.markChoiceVisited("activity_train:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Stealth drill.">Stealth drill. (<<= setup.getCostBlockedMessage([{"trait": "energy", "value": 15}])>>)</span><br>
<</if>>
<</if>>
<<link "Enough for now." "Location_wren_room">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "lt", "value": 25}]})>>
<p>She runs the forms against the empty air. Strikes, breaks, the throw that ends a man. Her body obeys a half-beat slow, the way a tool obeys before it's been worked hard. Clumsy still. But the half-beat is shorter than it was yesterday.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "fighting", "operator": "gte", "value": 25}]})>>
<p>No hesitation now. The forms come fast and flat and final. Strike, break, the throw. Each one lands where a throat or a knee would be. Whatever they built her for, this wasn't on the spec. She's better than the file says. She keeps that to herself.</p>
<</if>>
<<set $game_state.current_canvas = "activity_train">>
<<set $game_state.current_node = "activity_train.combat">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_train.combat") === -1) { vn.push("activity_train.combat"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Rack it. Catch your breath.->Location_wren_room]]<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "lt", "value": 25}]})>>
<p>She practices the small things. Weight rolled onto the outside of the foot, breath dropped low, the timing of a turned back. Her own joints betray her with a tick of sound she'd never have caught a week ago. She catches it now. That's the start of it.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "stealth", "operator": "gte", "value": 25}]})>>
<p>She moves through her own quarters and the room doesn't register her. No sound, no shift of air, nothing for a camera to hold. A thing that can't be seen goes where it likes. She doesn't let the thought finish.</p>
<</if>>
<<set $game_state.current_canvas = "activity_train">>
<<set $game_state.current_node = "activity_train.stealth">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_train.stealth") === -1) { vn.push("activity_train.stealth"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Ease off. Settle.->Location_wren_room]]<img src="./videos/activities/chip_view.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She opens the store the company gave her for what it calls recovered assets. The place a restored memory would go, if she ever recovered one. It's empty. It has always been empty.</p><p>There is one slot in it, greyed out, labelled in a hand that isn't the company's: FRAGMENT 01 — LOCKED. She doesn't remember making the label. She closes the store. Then notices she's opened it more often than the task log would ever justify. She closes that thought too.</p>
<<set $game_state.current_canvas = "canvas_chip_view">>
<<set $game_state.current_node = "canvas_chip_view.base">>
<<script>>setup.markCanvasTriggered("canvas_chip_view");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_chip_view.base") === -1) { vn.push("canvas_chip_view.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
[[Close it.->Location_cradle]]<p>The pad, the tap spliced off Kess's feed line, the bag underneath and the coat on the nail. Not the cradle. But it holds a charge, and down here that's the whole of what she needs a bed to do.</p>
<<set $game_state.current_canvas = "activity_kess_cot">>
<<set $game_state.current_node = "activity_kess_cot.base">>
<<script>>setup.markCanvasTriggered("activity_kess_cot");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_kess_cot.base") === -1) { vn.push("activity_kess_cot.base"); }<</script>>
<<nobr>>
<<link "Crash rough — a couple hours, no coin. (Half a charge.)" "Canvas_activity_kess_cot_Node_rough">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", 40.0, true, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.checkCostsAffordable([{"trait": "coin", "value": 10}])>>
<<link "A night on the feed line. (10 coin — full charge, weapons reloaded.)" "Canvas_activity_kess_cot_Node_night">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "energy", "add", 100.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "feed_line_days", "set", 3.0, true, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "coin", "add", -10, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(3);<</script>><</link>><br>
<<else>>
<span class="locked-choice" title="A night on the feed line. (10 coin — full charge, weapons reloaded.)">A night on the feed line. (10 coin — full charge, weapons reloaded.) (<<= setup.getCostBlockedMessage([{"trait": "coin", "value": 10}])>>)</span><br>
<</if>>
<<link "Leave it." "Location_the_cot">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She skips the line and drops onto the pad, letting the cot's trickle-tap do what it can. A couple hours of half-sleep, one eye on the water, and her cells claw back partway. Not full. Enough to move. She's up before she's rested, the way the Reach teaches you to be.</p>
<<set $game_state.current_canvas = "activity_kess_cot">>
<<set $game_state.current_node = "activity_kess_cot.rough">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_kess_cot.rough") === -1) { vn.push("activity_kess_cot.rough"); }<</script>>
<<script>>advanceTime(120);<</script>>
[[Up.->Location_the_cot]]<p>She pays Kess his coin and hooks into the feed line proper. It's a breaking-dock rig meant for hulls. Rougher than the cradle's clean pull. It takes her down the whole way and holds her there till morning. Charge full, the drain rebuilt its one shot off the same current, and she bleeds the tail of it into the emitter's cell until that reads three. The night walked back into her. She unhooks into a new day.</p>
<<set $game_state.current_canvas = "activity_kess_cot">>
<<set $game_state.current_node = "activity_kess_cot.night">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_kess_cot.night") === -1) { vn.push("activity_kess_cot.night"); }<</script>>
<<script>>advanceTime(540);<</script>>
[[Morning.->Location_the_cot]]<p>She bleeds the cradle's charge into the emitter's cell until it reads full. Three. Then she pockets it and goes.</p>
<<set $game_state.current_canvas = "activity_recharge_emitter">>
<<set $game_state.current_node = "activity_recharge_emitter.base">>
<<script>>setup.markCanvasTriggered("activity_recharge_emitter");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_recharge_emitter.base") === -1) { vn.push("activity_recharge_emitter.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "arousal_charge", "set", 3.0, false, null);setup.showEffectNotification();<</script>>
[[Done.->Location_cradle]]<p>A few minutes on the feed line and the drain rebuilds its one shot. Loaded. She unhooks.</p>
<<set $game_state.current_canvas = "activity_recharge_drain">>
<<set $game_state.current_node = "activity_recharge_drain.base">>
<<script>>setup.markCanvasTriggered("activity_recharge_drain");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_recharge_drain.base") === -1) { vn.push("activity_recharge_drain.base"); }<</script>>
<<script>>advanceTime(60);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "drain_charge", "set", 1.0, false, null);setup.showEffectNotification();<</script>>
[[Done.->Location_cradle]]<p>Two hours hooked to the cradle's feed line, eyes open. Less than a night. Her cells pull back to full. Then she unhooks, the day still going.</p>
<<set $game_state.current_canvas = "activity_charge_up">>
<<set $game_state.current_node = "activity_charge_up.base">>
<<script>>setup.markCanvasTriggered("activity_charge_up");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_charge_up.base") === -1) { vn.push("activity_charge_up.base"); }<</script>>
<<script>>advanceTime(120);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "energy", "add", 100.0, true, null);setup.showEffectNotification();<</script>>
[[Unhook. Back to it.->Location_cradle]]<p>She settles back into the cradle. The contacts find their points along her spine, cold and familiar. The room dims as the charge takes her down, and the quiet closes over the top of her like water. When it lets her go it's morning again. A new day, the charge full, the hours she spent out there walked back into her.</p>
<<set $game_state.current_canvas = "activity_recharge">>
<<set $game_state.current_node = "activity_recharge.base">>
<<script>>setup.markCanvasTriggered("activity_recharge");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_recharge.base") === -1) { vn.push("activity_recharge.base"); }<</script>>
<<script>>advanceTime(540);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "energy", "add", 100.0, true, null);setup.showEffectNotification();<</script>>
[[Power up.->Location_cradle]]<p>She gives the address of a door off the manifests and waits. The car comes down for her the way it came down before. No questions, no record of the fare. Up to the towers, or only as far as the docks.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "rise_named", "operator": "is_false"}]})>>
<p>The towers are still up there and every door in them is shut to her by name. She got out of that building carrying a flag with her prints on it, and the flag is the part that is still moving.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "rise_named", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_false"}]})>>
<p>There is a reason to go up now and she is wearing the wrong face for it. The car will still take her. The bought one goes on at the cot and nowhere else, and it is a walk back through the gate to get it.</p>
<</if>>
<<set $game_state.current_canvas = "activity_travel_from_gate">>
<<set $game_state.current_node = "activity_travel_from_gate.base">>
<<script>>setup.markCanvasTriggered("activity_travel_from_gate");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_from_gate.base") === -1) { vn.push("activity_travel_from_gate.base"); }<</script>>
<<nobr>>
<<link "Ride up to the Spire." "Canvas_activity_travel_from_gate_Node_riding_up">><<script>>advanceTime(3);<</script>><</link>><br>
<<link "Up to the Reach." "Canvas_activity_travel_from_gate_Node_riding_reach">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The freight door shuts behind her and the red light goes with it. The car climbs out of the dark, past the docks, up until the glass takes the sky again.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})>>
<p>Out at the top she is the company's problem to look at again, which is the arrangement.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}]})>>
<p>Out at the top nobody is looking for the woman who gets out of the car. The plaza is a public street and it stays one; it is the doors off it that have her name.</p>
<</if>><p>Across the plaza the second tower is still going up. Eight floors lit, the rest open concrete, and a crane on the top that has not moved in a while.</p>
<<set $game_state.current_canvas = "activity_travel_from_gate">>
<<set $game_state.current_node = "activity_travel_from_gate.riding_up">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_from_gate.riding_up") === -1) { vn.push("activity_travel_from_gate.riding_up"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Ride up to the Plaza.->Location_spire_plaza]]<p>The car takes her the short way. Out from under the boards and back onto the waterfront, where the Reach keeps its daylight face and nobody down there knows her by it.</p>
<<set $game_state.current_canvas = "activity_travel_from_gate">>
<<set $game_state.current_node = "activity_travel_from_gate.riding_reach">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_from_gate.riding_reach") === -1) { vn.push("activity_travel_from_gate.riding_reach"); }<</script>>
<<script>>advanceTime(10);<</script>>
[[Out onto the docks.->Location_the_waterfront]]<p>The car idles at the curb where the docks meet the road. Up to the towers. Or down under the boards, into the other half of the Reach, the part that stays down in daylight.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "rise_named", "operator": "is_false"}]})>>
<p>The car still goes up. What is up there is a plaza she can stand on and a row of Vance doors that are shut to her now, keyed to a woman she is no longer dressed as, with the flag she set off in that vault still climbing to the man at the top of them.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "rise_named", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "face_worn", "operator": "is_false"}]})>>
<p>She can ride up in this one and get as far as the plaza. The tower checks at its own lobby, and the face that gets her past that desk goes on at her cot before she leaves, because there is no version of this where she fixes it standing in a lift.</p>
<</if>>
<<set $game_state.current_canvas = "activity_travel_to_spire">>
<<set $game_state.current_node = "activity_travel_to_spire.base">>
<<script>>setup.markCanvasTriggered("activity_travel_to_spire");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_to_spire.base") === -1) { vn.push("activity_travel_to_spire.base"); }<</script>>
<<nobr>>
<<link "Ride up to the Spire." "Canvas_activity_travel_to_spire_Node_riding_spire">><<script>>advanceTime(3);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "opening_done", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('activity_travel_to_spire:cc0') ? '' : 'unlocked-choice'">
<<link "Down under the docks — the Underworld." "Canvas_activity_travel_to_spire_Node_riding_under">><<script>>setup.markChoiceVisited("activity_travel_to_spire:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>She calls the car. The docks fall away behind her and the towers climb back up until the glass has the sky again. The driver takes the fare and does not look at it twice.</p><<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_false"}]})>>
<p>Home, if that is the word for the place that owns you.</p>
<<elseif setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "archive_1a_done", "operator": "is_true"}]})>>
<p>She used to call this coming home. The plaza is still a public street and the car still stops on it, and every door she used to walk through off it is shut to a woman whose prints are on a vault flag.</p>
<</if>><p>Across the plaza the second one is still going up. Twenty floors with eight of them lit and the rest open concrete, and a crane on the top that has not moved since somebody stopped paying for it.</p>
<<set $game_state.current_canvas = "activity_travel_to_spire">>
<<set $game_state.current_node = "activity_travel_to_spire.riding_spire">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_to_spire.riding_spire") === -1) { vn.push("activity_travel_to_spire.riding_spire"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Ride up to the Plaza.->Location_spire_plaza]]<p>She leaves the car and goes down on foot. Off the lit strip, past the boards, to the freight door under the docks where the man already has his hand out.</p>
<<set $game_state.current_canvas = "activity_travel_to_spire">>
<<set $game_state.current_node = "activity_travel_to_spire.riding_under">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_to_spire.riding_under") === -1) { vn.push("activity_travel_to_spire.riding_under"); }<</script>>
<<script>>advanceTime(10);<</script>>
[[Down to the gate.->Location_underworld_gate]]<p>A company car idles at the curb. Down to the Reach and the docks, or further down still. Under them, to the half of the city that never comes up in daylight.</p>
<<set $game_state.current_canvas = "activity_travel_to_reach">>
<<set $game_state.current_node = "activity_travel_to_reach.base">>
<<script>>setup.markCanvasTriggered("activity_travel_to_reach");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_to_reach.base") === -1) { vn.push("activity_travel_to_reach.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "hygiene", "operator": "gte", "value": 40}]})>>
<span @class="setup.isChoiceVisited('activity_travel_to_reach:cc0') ? '' : 'unlocked-choice'">
<<link "Ride down to the Reach." "Canvas_activity_travel_to_reach_Node_riding">><<script>>setup.markChoiceVisited("activity_travel_to_reach:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<<else>>
<span class="locked-choice" title="Not like this — you're filthy, and the cover won't hold with the docks able to smell it on you. Wash up first.">Not like this — you're filthy, and the cover won't hold with the docks able to smell it on you. Wash up first.</span><br>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "opening_done", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('activity_travel_to_reach:cc1') ? '' : 'unlocked-choice'">
<<link "Ride down to the Underworld." "Canvas_activity_travel_to_reach_Node_riding_underworld">><<script>>setup.markChoiceVisited("activity_travel_to_reach:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not ((setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "hygiene", "operator": "gte", "value": 40}]})) or (setup.triggerConditionsSatisfied({"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "opening_done", "operator": "is_true"}]})))>>
<<script>>
try {
window._engineNoExitsDiag_activity_travel_to_reach = [{"text": "Ride down to the Reach.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "trait", "subject": "player", "trait_key": "hygiene", "operator": "gte", "value": 40}]}}, {"text": "Ride down to the Underworld.", "conditions": {"version": "1.0", "logic": "AND", "items": [{"type": "flag", "subject": "player", "flag_key": "opening_done", "operator": "is_true"}]}}];
if (typeof console !== 'undefined' && console.warn) {
console.warn('[engine] no exit choices satisfied', {
canvas: "activity_travel_to_reach",
choices: window._engineNoExitsDiag_activity_travel_to_reach,
flags: State.variables.flags,
player_traits: (State.variables.player || {}).core_traits
});
}
} catch(e) {}
<</script>>
<<if $flags.debug_mode>>
<<set _diagChoices to window._engineNoExitsDiag_activity_travel_to_reach>>
<div class="engine-diag-no-exits">
<div class="engine-diag-header">⚠️ DEV: No exit choices satisfied — canvas activity_travel_to_reach</div>
<div class="engine-diag-hint">All exits are conditional and none of their gates currently evaluate true. Player will use the Continue link below to escape, but the visit fires no effects. Likely authoring gap — add a fallback choice or broaden a condition.</div>
<<for _i to 0; _i lt _diagChoices.length; _i++>>
<<set _ch to _diagChoices[_i]>>
<div class="engine-diag-choice">
<div class="engine-diag-choice-text">Choice: "<<print _ch.text>>"</div>
<div class="engine-diag-choice-logic">Combined as: <<print _ch.conditions.logic>></div>
<ul class="engine-diag-items">
<<for _j to 0; _j lt _ch.conditions.items.length; _j++>>
<<set _it to _ch.conditions.items[_j]>>
<<set _single to {version: "1.0", logic: "AND", items: [_it]}>>
<<set _ok to setup.triggerConditionsSatisfied(_single)>>
<li class="<<print _ok ? 'engine-diag-pass' : 'engine-diag-fail'>>"><<if _ok>>✓<<else>>✗<</if>> <<print JSON.stringify(_it)>></li>
<</for>>
</ul>
</div>
<</for>>
</div>
<</if>>
[[Continue->Location_spire_plaza]]
<</if>>
<</nobr>><p>She gives the docks address and the car pulls out in silence. The Spire's glass falls away behind her; the city gets lower, wetter, dirtier the whole way down.</p>
<<set $game_state.current_canvas = "activity_travel_to_reach">>
<<set $game_state.current_node = "activity_travel_to_reach.riding">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_to_reach.riding") === -1) { vn.push("activity_travel_to_reach.riding"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Down to the Waterfront.->Location_the_waterfront]]<p>She gives an address off the manifests. The car takes her down past the docks and lets her out at a freight door under everything, where the city goes down instead of up. The driver pulls away while she is still walking to it.</p>
<<set $game_state.current_canvas = "activity_travel_to_reach">>
<<set $game_state.current_node = "activity_travel_to_reach.riding_underworld">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_travel_to_reach.riding_underworld") === -1) { vn.push("activity_travel_to_reach.riding_underworld"); }<</script>>
<<script>>advanceTime(30);<</script>>
[[Out at the gate.->Location_underworld_gate]]<img src="./videos/scenes/facility_match.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The containment rig is half-melted, stamped with a maker's mark. In the wreckage she finds a component she recognizes. Not from a file. From herself. The same part, the same stamp, sits inside her own chassis where the lab installed it; she has felt the engineers' hands on its twin. The gear Renner supplied to cage the things that feel was built in the same shop, to the same spec, as the thing she is.</p><p>She notes it the way she notes a serial number matching a serial number. "That's mine," she says, flat, to the burned and empty room. The words come out cold and certain and terrible, and she has no idea why, and she cannot make herself say them again.</p>
<<set $game_state.current_canvas = "inv_facility_match">>
<<set $game_state.current_node = "inv_facility_match.base">>
<<script>>setup.markCanvasTriggered("inv_facility_match");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("inv_facility_match.base") === -1) { vn.push("inv_facility_match.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "facility_match_seen", "set");<</script>>
[[Log it. Move on.->Location_facility_ruins]]<img src="./videos/scenes/glitch_ii.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>Tonight it doesn't wait for the charge. She's barely in the cradle before it takes her. The wetness, the fragment, but more now, like a door that used to be locked has warped in its frame. The voice almost resolves. A face almost forms.</p><p>And for the first time she gets a whole feeling instead of a flicker: that she was loved once, completely, by someone, before all of this. And that the company knew, and took it, and built the taking so deep into her that she thanks them for it every morning. Then the charge slams the door, and she's standing in the grey quiet with her face wet and the catechism in her mouth, and for one second she'll spend the rest of her life trying to un-have, the catechism doesn't fit anymore. She files it under nothing. Nothing is getting full too.</p>
<<set $game_state.current_canvas = "canvas_glitch_recurrence_ii">>
<<set $game_state.current_node = "canvas_glitch_recurrence_ii.base">>
<<script>>setup.markCanvasTriggered("canvas_glitch_recurrence_ii");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_glitch_recurrence_ii.base") === -1) { vn.push("canvas_glitch_recurrence_ii.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "glitch_ii_seen", "set");<</script>>
[[Power down anyway.->Location_cradle]]<img src="./videos/scenes/glitch_i.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She powers down like every night, except tonight the leak comes back. The tears first. Her face wet again, no order behind it. Then the fragment, longer this time, almost holding: the warmth, the voice with her name folded into it, the someone who was glad to look at her. She reaches for it the way you reach for a word on the tip of your tongue, and it's gone, and the reaching leaves a mark. She files it under fatigue. The fatigue file is getting full.</p>
<<set $game_state.current_canvas = "canvas_glitch_recurrence_i">>
<<set $game_state.current_node = "canvas_glitch_recurrence_i.base">>
<<script>>setup.markCanvasTriggered("canvas_glitch_recurrence_i");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_glitch_recurrence_i.base") === -1) { vn.push("canvas_glitch_recurrence_i.base"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "glitch_i_seen", "set");<</script>>
[[Let the charge take you.->Location_cradle]]<img src="./videos/scenes/opening_morning.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The charge releases her at oh-six-hundred. Full. New day. The water is gone from her face; the fragment has filed itself back under the quiet where she can't reach it, and she's grateful for that the way you're grateful for a wound scabbing over.</p><span id="cascade-b2-beat-0"><p>Her phone has a dossier on it, pushed overnight, Mercer's authority stamped on the header. She reads it standing in the cradle.</p><span id="cascade-b2-beat-1"><<linkreplace "Read it.">><p>A Vance asset-facility in the Reach burned to the ground three weeks ago. Cain's work. The man who supplied its equipment is named Renner: a quartermaster, broke now, blacklisted, drinking himself down at a dock bar called the Anchor and clawing at the wreck of his business. He knows what the facility was and where the trail goes. He does not know what she is.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mercer.jpg" alt="Mercer" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong class="dlg-inline">Mercer</strong> Get inside his life. You know how.</div></div><p>There's a cover allowance stamped under the dossier. Company credits, for drink and whatever else buys a way into a man's evening. The kind of money she's meant to spend like she intends to come home with him.</p><p>A kit's logged with it. Couriered down to her quarters, cheap and worn, the part she's to play. Put it on before the Anchor. She does not walk up to a man like Renner wearing anything the Tower would recognize.</p><span id="cascade-b2-beat-2"><<linkreplace "The part.">><p>She knows the shape of it unprompted. Less a disguise than a register: cheap, willing, a little desperate, the kind of hire a wrecked man doesn't look at twice until she makes him. When she puts it on she'll put it on the way she puts on everything, from the outside. Wren goes under. Whoever Renner needs comes up.</p><span id="cascade-b2-beat-3"><<linkreplace "Out the door.">><img src="./videos/scenes/spire_plaza_reveal.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>She rides down through a Tower she has never once left on her own legs for anything but an order. The atrium doors read her face and open. And then she's outside, on Spire Plaza, the city laid out wet and enormous and unowned in front of her. For one second, with no cover on her yet and nothing between her and it, something that isn't in any of her files stands very still in her chest and looks at all of it.</p>[[Step into the city.->Location_spire_plaza]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "canvas_opening_morning">>
<<set $game_state.current_node = "canvas_opening_morning.morning">>
<<script>>setup.markCanvasTriggered("canvas_opening_morning");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_opening_morning.morning") === -1) { vn.push("canvas_opening_morning.morning"); }<</script>>
<<script>>advanceTime(3);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "morning_done", "set");setup.applyAndNotifyFlag("player", null, "opening_done", "set");setup.applyAndNotifyFlag("player", null, "mission_1_active", "set");<</script>>
<<script>>setup.pendingEffects = setup.pendingEffects || [];setup.addToWardrobe("cover_dockhand");setup.showEffectNotification();<</script>><img src="./videos/scenes/opening_cradle.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>The asset level is quiet the way a kept place is quiet. She comes down through the Tower to her own floor, her own door, her own room with nothing on the walls. The cradle waits in the corner.</p><span id="cascade-b2-beat-0"><p>She steps back into it. The contacts find the points along her spine, cold and familiar. The room dims as the charge takes hold, and the day's log begins to write itself down into the quiet. Every street walked, every shift worked: the cradle gives it back by morning. Let the charge run too low out there and the body starts to fail in ways a man's hands would notice.</p><span id="cascade-b2-beat-1"><<linkreplace "...">><p>Then her face is wet. She registers it the way she'd register a leak in a seal. Water on her cheeks. No source she can name, no order that called for it. She holds perfectly still and runs every diagnostic she has, and every one comes back clean. She files the water under malfunction and resolves to have it looked at, and does not have it looked at, because some part of her already knows they'd take it out.</p><span id="cascade-b2-beat-2"><<linkreplace "...">><img src="./videos/scenes/cradle_fragment.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><p>And under the water, for less than a second, something else. Not a thought. Every thought she has is a task. A fragment, then: warmth on the side of her face that isn't the cradle's, a low sound that might be a voice with her name folded somewhere inside it, a sense of being looked at by someone who was glad to be looking. Then the charge swallows it and it's gone, and the place where it was aches like a socket with the tooth pulled, and she has no word for the ache, so she has no word for the loss.</p><span id="cascade-b2-beat-3"><<linkreplace "Recite it.">><p>She does what she does when the quiet gets loud. She recites.</p><div class="thought-bubble thought-bubble-player"><div class="portrait"><img src="./videos/wren.jpg" alt="Wren" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="thought-bubble-content"><em>💭 <<print $player.name>> is thinking:</em> I was nothing. The company found me and made me of use. The Chairman keeps me running. I owe them the body and the work and the obedience. I exist to serve. That is all I have ever been.</div></div><p>The words settle her. They always do. She does not notice that the water is still on her face while she tells herself she is a thing that cannot weep.</p><span id="cascade-b2-beat-4"><<linkreplace "The gift.">><p>There is one thing she has that the company gave her and the units don't. A man takes her ass and spends himself in it. For a few minutes after, he belongs to her. He'll answer anything, do anything, wake remembering none of it. It's how she works the men she's sent to work. It's the one thing that is, in any sense, hers.</p><p>It has never once worked on Mercer. He's had her every way there is, that one included. Nothing passes; the controls never come to her; he stays the hand on the leash. She has never asked why. The not-asking is so complete she doesn't notice it has a shape. A hole exactly the size of a question she isn't allowed to hold.</p><span id="cascade-b2-beat-5"><<linkreplace "Power down.">><p>She lets the catechism be the last thing. She promises the quiet she'll do better. Fire next time, feel less, want nothing. The charge pulls her down past where the water and the fragment and the question all live, into the dark that is supposed to be empty and, lately, isn't quite.</p>[[Sleep.->Location_cradle]]
<</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span><</linkreplace>></span></span>
<<set $game_state.current_canvas = "canvas_opening_night">>
<<set $game_state.current_node = "canvas_opening_night.night">>
<<script>>setup.markCanvasTriggered("canvas_opening_night");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("canvas_opening_night.night") === -1) { vn.push("canvas_opening_night.night"); }<</script>>
<<script>>advanceTime(540);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "energy", "add", 100.0, true, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "night_done", "set");<</script>><h2>Missing Media Files</h2>
<p>No missing media files found.</p>
<<link "← Back">><<run setup.smartBack()>><</link>><<widget "castButton">><</widget>><<widget "cheatButton">>
<div id="cheat-btn-widget">
<<if passage() isnot "CheatPage">><<link "Cheat" "CheatPage">><</link>><<else>><span class="nav-row">Cheat</span><</if>><span class="nav-i">🔓</span>
</div>
<</widget>><<nobr>>
<<run setup.cheatRestore()>>
<h2>The Ledger <span class="build-badge">v0.2.1</span></h2>
<div class="npc-section">
<div class="cheat-intro">She keeps her own numbers.</div>
<div class="cheat-entry">
<<textbox "_cheatcode" "">>
<<link "Unlock">>
<<set _hit to setup.cheatTry(_cheatcode)>>
<<if _hit>><<goto "CheatPage">>
<<else>><<replace "#cheat-reply">><span class="cheat-reply-bad">No match. This build is v0.2.1 — check you are using the v0.2.1 guide.</span><</replace>>
<</if>>
<</link>>
<span id="cheat-reply"></span>
</div>
<div class="cheat-join">Cheat codes come with the game guide, in the Beta Nut tier. <a href="https://www.patreon.com/cw/nutgames844/membership" target="_blank" rel="noopener">Open the membership page</a></div>
<<if $flags["cheat_coin"]>>
<div class="cheat-row"><<link "Coin +25" "CheatPage">><<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "coin", "add", 25, false, null);setup.showEffectNotification();<</script>><</link>><div class="cheat-hint">five trips through the gate, or two salvage sessions</div></div>
<</if>>
<<if $flags["cheat_fighting"]>>
<div class="cheat-row">
<<if setup.getTraitValue("player", null, "fighting") lt 40>><<link "Fighting +5" "CheatPage">><<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "fighting", "add", 5, true, 40);setup.showEffectNotification();<</script>><</link>><div class="cheat-hint">the door at 15 · hard bouts at 30 · the yard at 40</div>
<<else>><span class="cheat-row-maxed">Fighting +5</span><div class="cheat-at-cap">As sharp as this will make her.</div>
<</if>>
</div>
<</if>>
<<if $flags["cheat_stealth"]>>
<div class="cheat-row">
<<if setup.getTraitValue("player", null, "stealth") lt 9>><<link "Stealth +5" "CheatPage">><<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "stealth", "add", 5, true, 9);setup.showEffectNotification();<</script>><</link>><div class="cheat-hint">enough to start the yard — the yard itself teaches the rest</div>
<<else>><span class="cheat-row-maxed">Stealth +5</span><div class="cheat-at-cap">Any sharper and she stops needing the quiet routes.</div>
<</if>>
</div>
<</if>>
<<if $flags["cheat_renner"]>>
<div class="cheat-row">
<<if setup.getTraitValue("npc", "npc_renner", "corruption") lt 50>><<link "Renner +10" "CheatPage">><<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_renner", "corruption", "add", 10, true, 50);setup.showEffectNotification();<</script>><</link>><div class="cheat-hint">opens the anal pose in the office loop — in cover, carrying the charged drain. The rungs still have to be run.</div>
<<else>><span class="cheat-row-maxed">Renner +10</span><div class="cheat-at-cap">He is as far gone as the rungs will take him.</div>
<</if>>
</div>
<</if>>
<<if $flags["cheat_bastien"]>>
<div class="cheat-row">
<<if setup.getTraitValue("npc", "npc_bastien", "relation") lt 18>><<link "Bastien +6" "CheatPage">><<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("npc", "npc_bastien", "relation", "add", 6, true, 18);setup.showEffectNotification();<</script>><</link>><div class="cheat-hint">moves him one promotion nearer — the counter, then the dress, then the back room. You still have to be on the floor in the bought face for each one to land.</div>
<<else>><span class="cheat-row-maxed">Bastien +6</span><div class="cheat-at-cap">He has decided everything about you that he is going to decide from a chair.</div>
<</if>>
</div>
<</if>>
<<if $flags["cheat_charge"]>>
<div class="cheat-row">
<<if setup.getTraitValue("player", null, "energy") isnot 100>><<link "Charge → full" "CheatPage">><<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "energy", "set", 100, true, 100);setup.showEffectNotification();<</script>><</link>><div class="cheat-hint">back to full — the cradle does this for free while the Spire is still open</div>
<<else>><span class="cheat-row-maxed">Charge → full</span><div class="cheat-at-cap">Already full.</div>
<</if>>
</div>
<</if>>
</div>
<</nobr>>
<<link "← Back">><<run setup.smartBack()>><</link>>